Useful documents
https://github.com/noctuid/evil-guide
Header
Ensure file is loaded with lexical binding enabled.
;;; -*- lexical-binding: t -*-GUI settings
(when window-system
(blink-cursor-mode 0) ; Disable the cursor blinking
(scroll-bar-mode -1) ; Disable the scroll bar
(tool-bar-mode -1) ; Disable the tool bar
(tooltip-mode 0) ; Disable the tooltips
(menu-bar-mode -1))Defaults
(setq-default
ad-redefinition-action 'accept ; Silence warnings for redefinition
auto-window-vscroll nil ; Lighten vertical scroll
;;confirm-kill-emacs 'yes-or-no-p ; Confirm before exiting Emacs
cursor-in-non-selected-windows t ; Hide the cursor in inactive windows
delete-by-moving-to-trash t ; Delete files to trash
display-time-default-load-average nil ; Don't display load average
display-time-format "%H:%M" ; Format the time string
fill-column 80 ; Set width for automatic line breaks
help-window-select t ; Focus new help windows when opened
indent-tabs-mode nil ; Stop using tabs to indent
inhibit-startup-screen t ; Disable start-up screen
initial-scratch-message "" ; Empty the initial *scratch* buffer
left-margin-width 0 right-margin-width 0 ; Add left and right margins
make-backup-files nil ; No backup files
mouse-yank-at-point t ; Yank at point rather than pointer
ns-use-srgb-colorspace nil ; Don't use sRGB colors
recenter-positions '(5 top bottom) ; Set re-centering positions
scroll-margin 0 ; Add a margin when scrolling vertically
select-enable-clipboard t ; Merge system's and Emacs' clipboard
sentence-end-double-space t ; End a sentence after two spaces
show-trailing-whitespace nil ; Display trailing whitespaces
split-height-threshold nil ; Disable vertical window splitting
split-width-threshold nil ; Disable horizontal window splitting
tab-width 4 ; Set width for tabs
uniquify-buffer-name-style 'forward ; Uniquify buffer names
window-combination-resize t ; Resize windows proportionally
x-stretch-cursor t ; Stretch cursor to the glyph width
visible-bell 1 ; Disable beeps
bidi-display-reordering nil ; Make long lines faster by disabling bidi
case-fold-search t ; Searches should be case insensitive
visual-line-fringe-indicators t ; Show fringe indicator for visually wrapped lines
evil-respect-visual-line-mode t ; visual j/k, gj/gk hard line move
undo-tree-enable-undo-in-region nil) ; Prevent problem in undo-in-region
(setq disabled-command-function nil) ; Enable all disabled commands
(delete-selection-mode 1) ; Replace region when inserting text
(fset 'yes-or-no-p 'y-or-n-p) ; Replace yes/no prompts with y/n
(global-hl-line-mode 0) ; Hightlight current line
(global-subword-mode 0) ; Iterate through CamelCase words
(global-auto-revert-mode 1) ; Reload file if changed on disk
(mouse-avoidance-mode 'exile) ; Avoid collision of mouse with point if it gets too close
(put 'downcase-region 'disabled nil) ; Enable downcase-region
(put 'upcase-region 'disabled nil) ; Enable upcase-region
(fringe-mode '(8 . 0))
(cd "~/") ; Move to the user directoryCommon Lisp
(setq hfj/inferior-lisp-program "/usr/bin/sbcl")Frames
(setq default-frame-alist
'((left-fringe . 8)
(right-fringe . 0)
(menu-bar-lines . 0)
(tool-bar-lines . 0)
(horizontal-scroll-bars . nil)
(vertical-scroll-bars . nil)
(border-width . 0)))Leaders
(setq hfj/main-leader-key "SPC"
hfj/secondary-leader-key ",")Org-mode src languages
Some languages that I use that can be overridden in the locals.org file. These will be available in “s” snippet in org modes.
(setq hfj/yas-org-src-languages '("emacs-lisp"
"lisp"
"scheme"
"text"))Helpers
(defmacro hfj/after-config (&rest body)
`(add-hook 'hfj/post-config-hook #'(lambda () ,@body)))Basic config
Emacs 26 VCS
(when (string= invocation-name "emacs-26-vcs")
(setq with-editor-emacsclient-executable "/usr/bin/emacsclient-emacs-26-vcs"))Locals
(setq vc-follow-symlinks nil) ;; Prevent "follow link messages during startup"
(let ((org-filename (expand-file-name "locals.org" user-emacs-directory))
(el-filename (expand-file-name "locals.el" user-emacs-directory)))
(cond ((file-exists-p org-filename)
(org-babel-load-file org-filename))
((file-exists-p el-filename)
(load el-filename))))
(setq vc-follow-symlinks 'ask) ;; Restore defaultRemove startup info message
(defun display-startup-echo-area-message ()
(message ""))Appearance
Delight
(delight '((superword-mode "⁺" t)
(subword-mode "₊" t)
(eldoc-mode nil "eldoc")))Line numbering
;; (unless (version< emacs-version "26")
;; (setq display-line-numbers-type 'relative)
;; (add-hook 'prog-mode-hook 'display-line-numbers-mode))Line wrapping
;; When a line is too long to display, wrap it.
(hfj/after-config
(add-hook 'prog-mode-hook 'turn-on-visual-line-mode)
(add-hook 'text-mode-hook 'turn-on-visual-line-mode)
(add-hook 'org-mode-hook 'turn-on-visual-line-mode))Modeline
(setq-default mode-line-format
(list
"%l" ; Line
"%*" ; Modified marker
"%c" ; Column
'(:eval
(when (region-active-p)
(let* ((line-count (count-lines (region-beginning)
(min (1+ (region-end))
(point-max))))
(line-count-string (propertize
(format "%d" line-count)
'font-lock-face '(:foreground "White"))))
(cond ((= (region-beginning) (point))
(format " T%s#%s"
(propertize (number-to-string (line-number-at-pos (region-end)))
'face 'bold)
line-count-string))
((= (region-end) (point))
(format " F%s#%s"
(propertize (number-to-string (line-number-at-pos (region-beginning)))
'face 'bold)
line-count-string))))))
;; Percent done
" %p "
;; buffer name
"%b "
;; Size
"%I "
;; major mode
"%m "
;; minor modes
minor-mode-alist
;; filename
'(:eval (when buffer-file-truename
(concat " " (file-name-directory buffer-file-truename))))))
(custom-set-faces
'(mode-line ((t (:background "#2a2a28" :foreground "CadetBlue3" :box nil)))))Themes
(use-package dracula-theme
:demand t
:init
(load-theme 'dracula t t)
:config
(enable-theme 'dracula))(use-package boron-theme
:demand t
:init
(load-theme 'boron t t)
(enable-theme 'boron)
:config
(custom-set-faces
'(whitespace-trailing ((t (:background "dark gray" :foreground "#959595" :weight bold))))
'(ediff-current-diff-A ((t (:background "#330d0d"))))
'(ediff-fine-diff-A ((t (:background "#5a0d0d"))))
'(ediff-current-diff-B ((t (:background "#0d330d"))))
'(ediff-fine-diff-B ((t (:background "#0d4a0d"))))
'(ediff-current-diff-C ((t (:background "#0d331d"))))
'(ediff-fine-diff-C ((t (:background "#0d4a1d"))))
'(ediff-odd-diff-A ((t (:background "grey5"))))
'(ediff-even-diff-A ((t (:background "grey6"))))
'(ediff-odd-diff-B ((t (:background "grey5"))))
'(ediff-even-diff-B ((t (:background "grey6"))))
'(ediff-odd-diff-C ((t (:background "grey5"))))
'(ediff-even-diff-C ((t (:background "grey6"))))
'(whitespace-indentation ((t (:background "grey11"))))))
(use-package ample-theme
:demand t
:init
(load-theme 'ample t t)
(load-theme 'ample-flat t t)
(enable-theme 'ample-flat)
:config
(custom-set-faces
'(whitespace-trailing ((t (:background "dark gray" :foreground "#959595" :weight bold))))
'(ediff-current-diff-A ((t (:background "brown4"))))
'(ediff-current-diff-B ((t (:background "dark olive green"))))
'(ediff-current-diff-C ((t (:background "dark green"))))))
Custom file
Defaults/Overrides
(defvar hfj/markdown-command "~/.local/bin/pandoc")Load
(setq-default custom-file (expand-file-name ".custom.el"
user-emacs-directory))
(when (file-exists-p custom-file)
(load custom-file))Evil
Main
(use-package evil
:demand t
:init
(setq evil-want-integration nil)
:config
(evil-mode 1))Escape
(use-package evil-escape
:demand t
:after evil
:config
(setq-default evil-escape-key-sequence "kl"
evil-escape-unordered-key-sequence nil)
(evil-escape-mode))Indent-plus
(use-package evil-indent-plus
:after evil
:config
(define-key evil-inner-text-objects-map "i" 'evil-indent-plus-i-indent)
(define-key evil-outer-text-objects-map "i" 'evil-indent-plus-a-indent)
(define-key evil-inner-text-objects-map "I" 'evil-indent-plus-i-indent-up)
(define-key evil-outer-text-objects-map "I" 'evil-indent-plus-a-indent-up)
(define-key evil-inner-text-objects-map "J" 'evil-indent-plus-i-indent-up-down)
(define-key evil-outer-text-objects-map "J" 'evil-indent-plus-a-indent-up-down))Keybindings
https://github.com/noctuid/general.el
(use-package general
:demand t
:load-path "local-packages/general.el/"
:config
(setq general-override-states '(insert
emacs
hybrid
normal
visual
motion
operator
replace))
(general-override-mode))Numbers
(use-package evil-numbers
:after evil
:config
(define-key evil-normal-state-map (kbd "C-c +") 'evil-numbers/inc-at-pt)
(define-key evil-normal-state-map (kbd "C-c -") 'evil-numbers/dec-at-pt))Surround
(use-package evil-surround
:after evil
:config
(global-evil-surround-mode 1))Keybindings
(use-package evil-collection
:demand t
:after evil
:config
;; Make term buffers switch between char and line mode automatically.
(setq evil-collection-term-sync-state-and-mode-p t)
(evil-collection-init))Functions
Binding
(defun hfj/spc-bind (keys func &optional alias)
(let ((func-wrapper (cond (alias (list func :which-key alias))
(t func))))
(general-define-key
:states '(motion normal visual)
:keymaps 'override
:prefix hfj/main-leader-key
keys func-wrapper)))
(defun hfj/spc-bind-on-major (keymaps keys func &optional alias)
(let ((func-wrapper (cond (alias (list func :which-key alias))
(t func))))
(general-define-key
:states '(motion normal visual)
:keymaps keymaps
:prefix hfj/main-leader-key
keys func-wrapper)))
(defun hfj/spc-declare-subtree (keys alias)
(general-define-key
:states '(motion normal visual)
:keymaps 'override
:prefix hfj/main-leader-key
keys (list nil :which-key alias)))
(defun hfj/leader-bind (keymaps keys func &optional alias)
(let ((func-wrapper (cond (alias (list func :which-key alias))
(t func))))
(general-define-key
:states '(normal visual)
:keymaps keymaps
:prefix hfj/secondary-leader-key
keys func-wrapper)))
(defun hfj/minor-leader-bind (keymaps keys func &optional alias)
(let ((func-wrapper (cond (alias (list func :which-key alias))
(t func))))
(general-define-key
:definer 'minor-mode
:states '(normal visual)
:keymaps keymaps
:prefix hfj/secondary-leader-key
keys func-wrapper)))
(defun hfj/leader-declare-subtree (keymaps keys alias)
(general-define-key
:states '(normal visual)
:keymaps keymaps
:prefix hfj/secondary-leader-key
keys (list nil :which-key alias)))Diagonals
(defun hfj/set-char-at-current-line-pos (ch insert-pos)
(save-excursion
(beginning-of-line)
(let* ((start-pos (point))
end-pos
line-length)
(end-of-line)
(setf end-pos (point))
(setf line-length (- end-pos start-pos 1))
(cond ((< line-length insert-pos)
(insert-char ? (- insert-pos line-length 1)))
((<= insert-pos line-length)
(beginning-of-line)
(incf (point) insert-pos)
(delete-char 1)))
(insert-char ch))))
(defun hfj/diagonal-text-up-left (text)
"Replace text diagonally from current point."
(interactive "sWhat text? ")
(save-excursion
(let* ((text-length (length text))
(current-pos (point))
(rev-text (reverse text))
(line-pos (save-excursion (beginning-of-line) (- current-pos (point)))))
(loop for ch in (append rev-text nil)
for n downfrom line-pos to 0
do (hfj/set-char-at-current-line-pos ch n)
(previous-line)))))
(defun hfj/diagonal-text-up-right (text)
"Replace text diagonally from current point."
(interactive "sWhat text? ")
(save-excursion
(let* ((text-length (length text))
(current-pos (point))
(rev-text (reverse text))
(line-pos (save-excursion (beginning-of-line) (- current-pos (point)))))
(loop for ch in (append rev-text nil)
for n from line-pos
do (hfj/set-char-at-current-line-pos ch n)
(previous-line)))))
(defun hfj/diagonal-text-down-right (text)
"Replace text diagonally from current point."
(interactive "sWhat text? ")
(save-excursion
(let* ((text-length (length text))
(current-pos (point))
(line-pos (save-excursion (beginning-of-line) (- current-pos (point)))))
(loop for ch in (append text nil)
for n from line-pos
do (hfj/set-char-at-current-line-pos ch n)
(next-line)))))
(defun hfj/diagonal-text-down-left (text)
"Replace text diagonally from current point."
(interactive "sWhat text? ")
(save-excursion
(let* ((text-length (length text))
(current-pos (point))
(line-pos (save-excursion (beginning-of-line) (- current-pos (point)))))
(loop for ch in (append text nil)
for n downfrom line-pos to 0
do (hfj/set-char-at-current-line-pos ch n)
(next-line)))))Conversion
(defun hfj/point-seconds-to-date ()
"Grab thing at point and attempt to convert it from Unix timestamp seconds to a readable date."
(interactive)
(let* ((word (thing-at-point 'word 'no-properties))
(date-str (hfj/maybe-number-to-date word)))
(kill-new date-str)
(message "Date: %s" date-str)))
(defun hfj/maybe-number-to-date (str &optional format)
(let ((num (string-to-number str))
(format (or format "%F %H:%M:%S")))
(if (and num (< 0 num))
(format-time-string format num)
(error "Failed to parse %s" str))))Esc
;; esc quits
(defun minibuffer-keyboard-quit ()
"Abort recursive edit.
In Delete Selection mode, if the mark is active, just deactivate it;
then it takes a second \\[keyboard-quit] to abort the minibuffer."
(interactive)
(if (and delete-selection-mode transient-mark-mode mark-active)
(setq deactivate-mark t)
(when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
(abort-recursive-edit)))
(with-eval-after-load 'evil
(define-key evil-normal-state-map [escape] 'keyboard-quit)
(define-key evil-visual-state-map [escape] 'keyboard-quit)
(define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)
(global-set-key [escape] 'evil-exit-emacs-state))Escaping
(defun hfj/dash-escape-file-name (name)
"Convert filename into one without unacceptable characters or
spaces, replacing with dashes and underscores."
(replace-regexp-in-string
"--*"
"-"
(replace-regexp-in-string
"\\."
"-"
(replace-regexp-in-string
" "
"-"
(replace-regexp-in-string
"/"
"slash-"
(replace-regexp-in-string
"\\\\" ;; \
"_"
name))))))Eshell
(defun hfj/switch-to-eshell ()
"Switch to a new eshell, or existing using completing-read to display existing buffers."
(interactive)
(cl-labels ((make-eshell-with-name (name)
(let* ((window-to-use (selected-window))
(template "*eshell-")
(buffer-name (generate-new-buffer-name (concat template name "*")))
(eshell-buffer (unwind-protect (eshell t))))
(with-current-buffer eshell-buffer (rename-buffer buffer-name))
(set-window-buffer window-to-use eshell-buffer))))
(let* ((buffers (delete-if-not
#'(lambda (buf)
(eq (with-current-buffer buf major-mode) 'eshell-mode))
(with-persp-buffer-list () (buffer-list))))
(buffer-names-raw (sort (mapcar #'buffer-name buffers) #'string<))
(dirname (file-name-base (directory-file-name default-directory)))
(dirname-listing (concat "New from current dir: " dirname))
(buffer-names (cons dirname-listing buffer-names-raw))
(selection (completing-read "Eshell buffers: "
buffer-names
nil ; predicate
nil ; require-match
nil ; initial-input
nil ; hist
'default ; default value
)))
(when selection
(cond ((or (string= dirname-listing selection)
(eq selection 'default))
(make-eshell-with-name dirname))
((member selection buffer-names)
(switch-to-buffer selection))
(t
(make-eshell-with-name selection)))))))
(defun eshell/ll (&rest args)
"ls -l"
(eshell/ls (cons "-l" args)))
(defun eshell/la (&rest args)
"ls -la"
(eshell/ls (cons "-la" args)))
(defun eshell/e (&rest args)
"Edit a file."
(when (null args)
(error "Missing file arguments"))
(let ((file-paths (mapcar #'expand-file-name (eshell-flatten-list (reverse args)))))
(mapc #'find-file file-paths)))
(defun eshell/rename-shell (new-name)
(let* ((template "*eshell-")
(name (generate-new-buffer-name (concat template new-name "*"))))
(rename-buffer name)))
(defun hfj/eshell-insert-tramp-root ()
(interactive)
(insert-and-inherit
(let* ((parts (s-split ":" default-directory))
(parts-count (length parts)))
(cond ((< 1 parts-count)
(concat (s-join ":" (seq-take parts (1- parts-count))) ":/"))
(t
"/")))))
(defun hfj/find-eshell-root ()
"Return the root directory for current path in eshell."
(let* ((parts (s-split ":" default-directory))
(parts-count (length parts)))
(cond ((< 1 parts-count)
(concat (s-join ":" (seq-take parts (1- parts-count))) ":/"))
(t
"/"))))
(defun hfj/eshell-hook ()
(define-key eshell-mode-map (kbd "C-c /") 'hfj/eshell-insert-tramp-root)
(setq pcomplete-cycle-completions nil))
Filename
(defun hfj/buffer-file-name-and-line ()
(when buffer-file-name
(concat (buffer-file-name) ":" (number-to-string (line-number-at-pos)))))
(defun hfj/show-and-copy-buffer-filename ()
"Show the full path to the current file in the minibuffer and in the clipboard."
(interactive)
(let ((file-name (or (buffer-file-name)
(error "Buffer not visiting a file"))))
(message file-name)
(kill-new file-name)))
(defun hfj/show-and-copy-buffer-filename-and-line ()
"Show the full path to the current file and line in the minibuffer and place in the clipboard."
(interactive)
(let ((file-name-and-line (or (hfj/buffer-file-name-and-line)
(error "Buffer not visiting a file"))))
(message file-name-and-line)
(kill-new file-name-and-line)))Formatting
(defun hfj/remove-double-newlines ()
"Replace multiple blank lines with a single one."
(interactive)
(goto-char (point-min))
(while (re-search-forward "\\(^\\s-*$\\)\n" nil t)
(replace-match "\n")
(forward-char 1)))Line Endings
(defun hfj/set-unix-line-endings ()
"Change the current buffer to Unix line-ends."
(interactive)
(set-buffer-file-coding-system 'unix t))
(defun hfj/set-dos-line-endings ()
"Change the current buffer to DOS line-ends."
(interactive)
(set-buffer-file-coding-system 'dos t))
(defun hfj/set-mac-line-endings ()
"Change the current buffer to Mac line-ends."
(interactive)
(set-buffer-file-coding-system 'mac t))Numeric
(defun hfj/base-convert (number from-base to-base)
"Convert a number from one base to another."
(interactive "sNumber to convert: \nnFrom base: \nnTo base: ")
(let* ((full-numbers "0123456789abcdefghijklmnopqrstuvwxyz")
(from-numbers (substring full-numbers 0 from-base))
(to-numbers (substring full-numbers 0 to-base))
(from-number (cl-loop for src-digit across (downcase (reverse number))
for poly from 0
for pos = (seq-position from-numbers src-digit)
do (when (null pos)
(error "Invalid digit '%c'" src-digit))
sum (* pos (expt from-base poly))))
(top-poly (cl-loop for poly from 0
for divisor = (expt to-base poly)
when (< from-number divisor)
return (1- poly)))
(result (let ((to-digits '()))
(cl-loop for num = from-number then rem
for poly from top-poly downto 0
for divisor = (expt to-base poly)
for rem = (cl-rem num divisor)
for result = (/ num divisor)
do (push (elt to-numbers result) to-digits))
(seq-into (nreverse to-digits) 'string))))
(kill-new result)
(message "\"%s\" from base %d to base %d is \"%s\"" number from-base to-base result)
result))
(defun hfj/show-binary-flags (number)
"Convert number to bit flags and display in new buffer."
(interactive "nNumber to explain: ")
(let* ((top-poly (cl-loop for poly from 0
for divisor = (expt 2 poly)
when (< number divisor)
return (1- poly)))
(flags (let ((to-digits '()))
(cl-loop for num = number then rem
for poly from top-poly downto 0
for divisor = (expt 2 poly)
for rem = (cl-rem num divisor)
for result = (/ num divisor)
do (push result to-digits))
to-digits))
(new-buffer (generate-new-buffer (format "*Binary flags %d*" number))))
(with-current-buffer new-buffer
(insert (format "%d as binary flag\n\n" number))
(insert "Position | Position Value\n")
(insert "---------+----------------\n")
(cl-loop for top = (expt 2 top-poly)
for b in flags
for i from 0
for value = (expt 2 i)
do (when (= b 1)
(insert (format "%8d | %d\n" i value))))
(insert "\nAll:\n")
(insert "Position | Flag | Position Value\n")
(insert "---------+------+----------------\n")
(cl-loop for top = (expt 2 top-poly)
for b in flags
for i from 0
for value = (expt 2 i)
do (insert (format "%8d | %d | %d\n" i b value)))
(setf (point) (point-min)))
(display-buffer-below-selected new-buffer nil)))Org
(defun hfj-org-mode/over-lines (f lines &optional initial-value)
(do ((line-start 0 (1+ line-end))
(line-end (search "\n" lines)
(search "\n" lines :start2 (1+ line-end)))
(acc initial-value))
((null line-end) acc)
(setq acc
(funcall f acc (substring lines line-start line-end)))))
(defun hfj-org-mode/get-org-block-contents ()
(cl-labels
((get-block-contents
()
(save-excursion
(let ((start (re-search-backward "^[ \t]*#\\+BEGIN_SRC" nil t))
(end (re-search-forward "^[ \t]*#\\+END_SRC" nil t)))
(when end
(setf (point) start)
(setq start (search-forward "\n"))
(setf (point) end)
(setq end (1+ (search-backward "\n")))
(buffer-substring start end)))))
(find-trim-length (contents)
(hfj-org-mode/over-lines
#'(lambda (trim-length line)
(let* ((trim-line (s-trim-left line))
(trim-line-lenth (length trim-line))
(diff (- (length line) trim-line-lenth)))
(if (and (or (null trim-length) (< diff trim-length))
(> trim-line-lenth 0))
diff
trim-length)))
contents))
(trim-lines (contents trim-length)
(apply 'concat (nreverse (hfj-org-mode/over-lines
#'(lambda (new-lines line)
(cons (concat (when (< trim-length (length line))
(substring line trim-length))
"\n")
new-lines))
contents))))
(unescape (contents)
(replace-regexp-in-string "^\\([ \t]*\\),\\([*#]\\)"
"\\1\\2"
contents)))
(let ((block-contents (get-block-contents)))
(if (null block-contents)
(error "Unable to find block.")
(let ((trimmed-contents (let ((trim-length (find-trim-length block-contents)))
(if (or (null trim-length) (= 0 trim-length))
block-contents
(trim-lines block-contents trim-length)))))
(unescape trimmed-contents))))))
(defun hfj-org-mode/yank-org-src-block ()
"Copy the contents of the current org-mode src block to the kill ring."
(interactive)
(cl-labels ((line-count (contents)
(hfj-org-mode/over-lines #'(lambda (acc line) (1+ acc)) contents 0))
(inform (contents)
(let ((num-lines (line-count contents)))
(if (= 1 num-lines)
(message "Copied 1 line.")
(message "Copied %d lines." num-lines)))))
(let ((to-kill (hfj-org-mode/get-org-block-contents)))
(kill-new to-kill)
(inform to-kill))))Radio
(defun hfj/play-link (link)
"Load link in new window"
(split-window-below)
(windmove-down)
(let* ((arg-string (concat "mpv --quiet " (shell-quote-argument link) "; exit; \n"))
(buffer (ansi-term (getenv "SHELL")))
(proc (get-buffer-process buffer)))
(comint-send-string buffer arg-string)
(windmove-up)
(set-process-sentinel proc
`(lambda (process event)
(when (string= event "finished\n")
(with-current-buffer ,buffer
(kill-buffer-and-window)))))))
(defun hfj/make-link-player (link)
#'(lambda ()
(interactive)
(hfj/play-link link)))Path
(defun hfj/split-path (path)
(s-split "/" path t))
(defun hfj/join-path (path-parts)
(s-join "/" path-parts))
(defun hfj/is-subpath-of (path parent-path)
"Determine if a path is child path of another. When it is,
return the relative path from the parent."
(let ((path-parts (hfj/split-path (expand-file-name path)))
(parent-path-parts (hfj/split-path (expand-file-name parent-path))))
(loop for p in path-parts
and pp in parent-path-parts
and remaining = path-parts then (cdr remaining)
when (not (string= p pp))
return nil
finally return (hfj/join-path remaining))))Shell
(defun hfj/eshell-here ()
(interactive)
(let ((window-to-use (selected-window))
(eshell-buffer (unwind-protect (eshell t))))
(set-window-buffer window-to-use eshell-buffer)))
(defun hfj/shell-here ()
(interactive)
(let ((window-to-use (selected-window))
(config (current-window-configuration))
(new-shell-buffer (generate-new-buffer (generate-new-buffer-name "*shell"))))
(unwind-protect
(shell new-shell-buffer)
(set-window-configuration config))
(set-window-buffer window-to-use new-shell-buffer)))
(defun hfj/switch-to-shell ()
(interactive)
(let* ((buffers (delete-if-not #'(lambda (buf)
(eq (with-current-buffer buf major-mode) 'shell-mode))
(with-persp-buffer-list () (buffer-list))))
(buffer-names (sort (mapcar #'buffer-name buffers) #'string<)))
(let ((selection (completing-read "Shell buffers: " buffer-names)))
(when selection
(cond ((member selection buffer-names)
(switch-to-buffer selection))
(t
(let* ((window-to-use (selected-window))
(template "*shell-")
(config (current-window-configuration))
(new-shell-buffer (generate-new-buffer (concat template selection "*"))))
(unwind-protect
(shell new-shell-buffer)
(set-window-configuration config))
(set-window-buffer window-to-use new-shell-buffer))))))))
(defun hfj/ansi-term-here ()
(interactive)
(let ((window-to-use (selected-window))
(config (current-window-configuration))
(name (generate-new-buffer-name "*ansi-term"))
(new-shell-buffer))
(unwind-protect
(setq new-shell-buffer (ansi-term "/bin/bash" name))
(set-window-configuration config))
(set-window-buffer window-to-use new-shell-buffer)))
(defun hfj/multi-term-here ()
(interactive)
(let ((window-to-use (selected-window))
(config (current-window-configuration))
(new-shell-buffer))
(unwind-protect
(setq new-shell-buffer (multi-term))
(set-window-configuration config))
(set-window-buffer window-to-use new-shell-buffer)))String
Duplicate-n
(defun hfj/duplicate-n (times start)
"Duplicate the text in the current kill n times. The text of %i is replaced with the incrementing number."
(interactive "nTimes to duplicate: \nnStarting at: ")
(let ((text (car kill-ring-yank-pointer)))
(dotimes (i times)
(insert (s-replace-all `(("%i" . ,(number-to-string (+ i start)))) text)))))Replace word at point
(defun hfj/replace-word-at-point ()
(interactive)
(er/mark-word)
(let* ((str (buffer-substring (region-beginning) (region-end)))
(replacement (read-string "Replacement: " str)))
(replace-string str replacement t (point-min) (point-max))))
(defun hfj/replace-symbol-at-point ()
(interactive)
(er/mark-symbol)
(let* ((str (buffer-substring (region-beginning) (region-end)))
(replacement (read-string "Replacement: " str)))
(replace-string str replacement t (point-min) (point-max))))Change case
(defun hfj/snake-case->lower-camel-case (s)
(let* ((words (split-string s "_"))
(result (list (car words))))
(dolist (word (cdr words) (s-join "" (nreverse result)))
(push (capitalize (downcase word)) result))))
(defun hfj/snake-case->camel-case (s)
(let (result)
(dolist (word (split-string s "_") (s-join "" (nreverse result)))
(push (capitalize (downcase word)) result))))
(defun hfj/underscorify (s &optional sep start)
"Convert CamelCase to underscores."
(let ((case-fold-search nil))
(while (string-match "[A-Z]" s (or start 1))
(setq s (replace-match (concat (or sep "_")
(downcase (match-string 0 s)))
t nil s)))
(downcase s)))
(defun hfj/filename-as-class ()
(hfj/snake-case->camel-case
(hfj/underscorify
(file-name-base buffer-file-name))))Generate random sequence (random username/password)
(defun hfj/seq-random-selection (seq out-length)
"Create a new sequence from random elements of another sequence."
(let ((len (length seq)))
(coerce (cl-loop for n from 1 to out-length
for i = (random len)
collect (elt seq i))
(type-of seq))))
(defun hfj/generate-basic-password (len)
"Create a random password from uppercase and lowercase characters and numbers."
(interactive "nPassword length: ")
(let ((password (hfj/seq-random-selection
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
len)))
(kill-new password)
(message "Password copied to clipboard.")))
(defun hfj/generate-extended-password (len)
"Create a random password from uppercase and lowercase characters, numbers, and funny chars."
(interactive "nPassword length: ")
(let ((password (hfj/seq-random-selection
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()\"' +-\\[]<>,./?;:{}|_=~`"
len)))
(kill-new password)
(message "Password copied to clipboard.")))Symlinking
(defun hfj/symlink-to-alternate-dir (alternate-dir-name)
(cl-labels ((make-path (rev-parts)
(mapconcat 'identity (reverse rev-parts) "/"))
(append-path (dir filename)
(mapconcat 'identity (list dir filename) "/"))
(find-alt-path (dir-name dir-parts &optional processed-parts)
(if (null dir-parts)
nil
(let ((archive-path (make-path (cons dir-name dir-parts))))
(if (file-exists-p archive-path)
(append (reverse (cdr processed-parts))
(list dir-name)
dir-parts)
(find-alt-path dir-name
(cdr dir-parts)
(cons (car dir-parts)
processed-parts))))))
(depth-to-relative (depth)
(if (> depth 0)
(concat "../" (depth-to-relative (1- depth)))
nil))
(dup (val count)
(unless (zerop count)
(cons val (dup val (1- count)))))
(rel-path (from-parts to-parts &optional unique)
(if (equal from-parts to-parts)
(make-path (append (reverse unique)
(dup ".." (length unique))))
(rel-path (cdr from-parts)
(cdr to-parts)
(cons (car from-parts) unique)))))
(let* ((parts (split-string buffer-file-name "/"))
(rev-parts (reverse parts))
(file-name (car rev-parts))
(dir-parts (cdr rev-parts))
(archive-dir-parts (find-alt-path alternate-dir-name dir-parts)))
(if (null archive-dir-parts)
(error "Unable to find alternate path.")
(let* ((target-dir (make-path archive-dir-parts))
(target-path (append-path target-dir file-name))
(source-dir (rel-path dir-parts archive-dir-parts))
(source-path (append-path source-dir file-name)))
(make-symbolic-link (mapconcat 'identity
(list (rel-path dir-parts archive-dir-parts)
file-name)
"/")
(make-path (cons file-name archive-dir-parts))))))))Timer
(defun hfj/parse-short-time (time-string)
"Convert short time form to seconds. Example \"1h1m\" is 3660.
s: seconds
m: minutes
h: hours
d: days
w: weeks
M: months
y: years"
(let ((seconds 0)
(start 0)
(numbers nil)
(operator nil)
(total 0)
(time-string-length (length time-string)))
(save-match-data
(while (< start time-string-length)
(cond ((string-match "\\([0-9]+\\)\\([smhdw]\\)" time-string start)
(let* ((numbers (string-to-number (match-string 1 time-string)))
(operator (match-string 2 time-string))
(multiplier (cond ((string= operator "s") 1)
((string= operator "m") 60)
((string= operator "h") (* 60 60))
((string= operator "d") (* 60 60 24))
((string= operator "w") (* 60 60 24 7))
((string= operator "M") (* 60 60 24 30))
((string= operator "y") (* 60 60 24 365))
(t (error "Invalid multiplier %s" operator)))))
(setq start (match-end 0))
(setq total (+ total (* numbers multiplier)))))
(t
(error "Invalid time pattern: %s" (substring time-string start))))))
total))
(defun hfj/message-at-time (msg time)
"Message user at a certain time."
(interactive "sMessage: \nsTime (##:## or # second/minute): ")
(let ((time-or-seconds (or (ignore-errors (hfj/parse-short-time time))
time))
(start-time (current-time)))
(run-at-time time-or-seconds nil
(lambda ()
(let ((output-msg (format "Timer message from %s ago:\n%s "
(format-seconds "%Y, %D, %H, %M, %z%S"
(float-time (time-subtract (current-time) start-time)))
msg)))
(start-process "notify-send" nil "notify-send" output-msg)
(message-box output-msg))))))Languages
C/C++
(defun hfj/c-mode-common-hook ()
(modify-syntax-entry ?_ "w" c-mode-syntax-table)
(modify-syntax-entry ?_ "w" c++-mode-syntax-table)
(dolist (mode '(c-mode-map c++-mode-map))
(hfj/leader-bind mode "o" 'ff-get-other-file "visit other file")))
(add-hook 'c-mode-common-hook 'hfj/c-mode-common-hook)Common Lisp
(use-package slime
:defer 1
:init
(setq inferior-lisp-program hfj/inferior-lisp-program)
(add-hook 'slime-repl-mode-hook #'hfj/slime-repl-mode-hook)
;; (add-hook 'slime-load-hook #'hfj/slime-mode-hook)
;; Start slime on startup
;; (save-window-excursion
;; (slime))
;; Lisp files connect to slime automatically
(add-hook 'slime-mode-hook
(lambda ()
(unless (slime-connected-p)
(save-excursion (slime)))))
:config
(slime-setup '(slime-fancy
slime-company
slime-indentation)) ;; slime overrides cl-indent without slime-indentation
(defmacro slime-eval-in-thread (&rest body)
`(slime-eval
`(cl:progn
(bt:make-thread
(cl:lambda () ,,@body))
nil))))
;; Example usage:
;; (slime-eval-in-thread
;; `(cl:progn (hackmud:send-text ,(concat "user " user))
;; (cl:sleep 1.9)
;; (hackmud:send-text-q "sys.specs")
;; (cl:sleep 1.5)
;; (hackmud:send-text-q "accts.balance")))
(defun hfj/slime-repl-mode-hook ()
(slime-eval
`(cl:progn
(ql:quickload :bt-semaphore :silent t)
(cl:setf cl:*read-default-float-format* 'cl:double-float))))
(use-package slime-company
:after slime)
(defun hfj/common-lisp-mode-hook ()
(put 'defcommand 'common-lisp-indent-function (get 'defun 'common-lisp-indent-function))
(set (make-local-variable 'lisp-indent-function) 'common-lisp-indent-function))
;; Indent common lisp code correctly
(add-hook 'lisp-mode-hook 'hfj/common-lisp-mode-hook)Emacs Lisp
(defun hfj/emacs-lisp-mode-hook ()
(modify-syntax-entry ?- "w" emacs-lisp-mode-syntax-table)
(modify-syntax-entry ?/ "w" emacs-lisp-mode-syntax-table)
(dolist (pair '(;; ("<=" . #x2264) ; ≤
;; (">=" . #x2265) ; ≥
("defun" . #x2a0d) ; ⨍
))
(push pair prettify-symbols-alist))
(turn-on-prettify-symbols-mode)
(smartparens-mode)
;; Don't pair single quotes
(sp-local-pair 'emacs-lisp-mode "'" nil :actions nil)
(aggressive-indent-mode))
(use-package emacs-lisp-mode
:ensure nil
:delight emacs-lisp-mode "Emacs Lisp"
:init
(add-hook 'emacs-lisp-mode-hook 'hfj/emacs-lisp-mode-hook)
:config
(delight 'lisp-interaction-mode "Lisp Interaction"))
(use-package ielm
:ensure nil
:hook (ielm-mode . (lambda () (setq-local scroll-margin 0))))Haskell
(use-package haskell-mode
:mode (("\\.hs$" . haskell-mode)
("\\.lhs$" . haskell-mode)
("\\.hsc$" . haskell-mode)
("\\.cpphs$" . haskell-mode)
("\\.c2hs$" . haskell-mode)))
(use-package intero
:after haskell-mode
:hook (haskell-mode . intero-mode))Javascript
(use-package js2-mode
:mode (("\\.js" . js2-mode))
:config
(add-hook 'js2-mode-hook #'js2-imenu-extras-mode)
(add-hook 'js2-mode-hook #'hfj/js2-hook))
(use-package js2-refactor
:after js2-mode)
(use-package xref-js2
:after js2-mode)
(with-eval-after-load 'js2-mode
(with-eval-after-load 'smartparens
(sp-with-modes '(js2-mode)
(sp-local-pair "/*" "*/" :post-handlers '(:add ("||\n[i]" "RET")))
(sp-local-pair "{" nil :post-handlers '(:add ("||\n[i]" "RET")))
(sp-local-pair "(" nil :post-handlers '(:add ("||\n[i]" "RET"))))))
(defun hfj/js2-hook ()
(smartparens-mode)
(turn-on-visual-line-mode)
(setq indent-tabs-mode nil
tab-width 4
c-basic-offset 4)
(company-mode t)
(font-lock-add-keywords nil
`((,(rx (not (any ?= ?!)) (group ?=) (not (any ?= ?> ?<))) 1 'hi-red-b prepend))))
Lisp
(defun hfj/lisp-mode-hook ()
(modify-syntax-entry ?- "w" lisp-mode-syntax-table)
(modify-syntax-entry ?/ "w" lisp-mode-syntax-table)
(dolist (pair '(;; ("<=" . #x2264) ; ≤
;; (">=" . #x2265) ; ≥
("defun" . #x2a0d) ; ⨍
))
(push pair prettify-symbols-alist))
(turn-on-prettify-symbols-mode)
(smartparens-mode)
;; Don't pair single quotes
(sp-local-pair 'lisp-mode "'" nil :actions nil)
(aggressive-indent-mode)
(require 'slime)
(require 'slime-company))
(use-package lisp-mode
:ensure nil
:delight lisp-mode "Lisp"
:init
(add-hook 'lisp-mode-hook 'hfj/lisp-mode-hook))Markdown
(use-package markdown-mode
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode))
:init (setq markdown-command hfj/markdown-command))PHP
(use-package php-mode
:mode (("\\.php" . php-mode))
:init
(add-hook 'php-mode-hook 'hfj/php-mode-hook)
:config
(setq php-template-compatibility nil))
(use-package company-php
:after php-mode)
(use-package ac-php
:after php-mode)
(with-eval-after-load 'php-mode
(with-eval-after-load 'smartparens
(sp-with-modes '(php-mode)
(sp-local-pair "/**" "*/" :post-handlers '(("| " "SPC")
(hfj/php-handle-docstring "RET")))
(sp-local-pair "/*." ".*/" :post-handlers '(("| " "SPC")))
(sp-local-pair "{" nil :post-handlers '(:add ("||\n[i]" "RET")))
(sp-local-pair "(" nil :post-handlers '(:add ("||\n[i]" "RET"))))))
(defun hfj/php-mode-hook ()
(require 'ac-php)
(require 'company-php)
(smartparens-mode)
(setq indent-tabs-mode nil
tab-width 4
c-basic-offset 4)
(company-mode t)
(ac-php-core-eldoc-setup) ;; enable eldoc
(make-local-variable 'company-backends)
(add-to-list 'company-backends 'company-ac-php-backend)
(modify-syntax-entry ?_ "w" php-mode-syntax-table)
(font-lock-add-keywords nil
`((,(rx (not (any ?= ?! ?> ?< ?* ?+ ?- ?/))
(group (zero-or-one (any ?* ?+ ?- ?/)) ?=)
(not (any ?= ?> ?<)))
1 ;; group
'hi-red-b ;; color
prepend))))
(defun hfj/php-handle-docstring (&rest _ignored)
(-when-let (line (save-excursion
(forward-line)
(thing-at-point 'line)))
(cond
;; variable
((string-match (rx (or "private" "protected" "public" "var") (1+ " ") (group "$" (1+ alnum))) line)
(let ((var-name (match-string 1 line))
(type ""))
;; try to guess the type from the constructor
(-when-let (constructor-args (my-php-get-function-args "__construct" t))
(setq type (or (cdr (assoc var-name constructor-args)) "")))
(insert "* @var " type)
(save-excursion
(insert "\n"))))
((string-match-p "function" line)
(save-excursion
(let ((args (save-excursion
(forward-line)
(my-php-get-function-args nil t))))
(--each args
(when (my-php-should-insert-type-annotation (cdr it))
(insert (format "* @param %s%s\n"
(my-php-translate-type-annotation (cdr it))
(car it))))))
(let ((return-type (save-excursion
(forward-line)
(my-php-get-function-return-type))))
(when (my-php-should-insert-type-annotation return-type)
(insert (format "* @return %s\n" (my-php-translate-type-annotation return-type))))))
(re-search-forward (rx "@" (or "param" "return") " ") nil t))
((string-match-p ".*class\\|interface" line)
(save-excursion (insert "\n"))
(insert "* ")))
(let ((o (sp--get-active-overlay)))
(indent-region (overlay-start o) (overlay-end o)))))Racket
(defun hfj/racket-mode-hook ()
(smartparens-mode)
;; Don't pair single quotes
(sp-local-pair 'racket-mode "'" nil :actions nil)
(aggressive-indent-mode)
(rainbow-delimiters-mode)
(show-smartparens-mode))
(defun hfj/racket-repl-mode-hook ()
(smartparens-mode)
;; Don't pair single quotes
(sp-local-pair 'racket-mode "'" nil :actions nil)
(company-mode))
(use-package racket-mode
:mode (("\\.rkt" . racket-mode))
:delight racket-mode "Racket"
:init
(add-hook 'racket-mode-hook 'hfj/racket-mode-hook)
(add-hook 'racket-repl-mode-hook 'hfj/racket-repl-mode-hook))Scheme
(defun hfj/scheme-mode-hook ()
(modify-syntax-entry ?- "w" scheme-mode-syntax-table)
(modify-syntax-entry ?/ "w" scheme-mode-syntax-table)
;; Don't pair single quotes
(sp-local-pair 'scheme-mode "'" nil :actions nil)
(smartparens-mode)
(aggressive-indent-mode)
(rainbow-delimiters-mode)
(show-smartparens-mode))
(use-package scheme-mode
:ensure nil
:delight scheme-mode "Scheme"
:mode (("\\.scm" . scheme-mode)
("\\.ss" . scheme-mode))
:init
(add-hook 'scheme-mode-hook 'hfj/scheme-mode-hook)
(setq scheme-program-name "gosh -i"))Shell scripts
(use-package sh-mode
:mode (("\\.sh" . sh-mode))
:ensure nil
:init
(add-hook 'sh-mode-hook 'hfj/sh-mode-hook))
(defun hfj/sh-mode-hook ()
(smartparens-mode)
(sp-local-pair 'sh-mode "{" nil :post-handlers '(:add ("||\n[i]" "RET")))
(sp-local-pair 'sh-mode "(" nil :post-handlers '(:add ("||\n[i]" "RET"))))Features
Alert
(use-package alert
:commands alert
:init
(defun alert-long (&rest rest)
(let ((alert-fade-time 0))
(apply #'alert rest)))
:config
(setq alert-default-style 'libnotify))Annotate
(use-package annotate
:defer 1
:commands (annotate-mode annotate-annotate))Auto-complete (company)
Company
(defvar hfj/company-fill-column nil)
(defun hfj/company-start-hook (action)
)
(defun hfj/company-stop-hook (result)
)
(use-package company
:commands company-mode
:init
(add-hook 'prog-mode-hook 'company-mode)
:config
(setq-default
company-idle-delay .2
company-minimum-prefix-length 1
company-require-match nil
company-tooltip-align-annotations t)
(company-quickhelp-mode)
(add-hook 'company-completion-started-hook 'hfj/company-start-hook)
(add-hook 'company-completion-finished-hook 'hfj/company-stop-hook)
(add-hook 'company-completion-cancelled-hook 'hfj/company-stop-hook))
(use-package company-quickhelp
:after company)
(use-package company-dabbrev
:demand t
:ensure nil
:after company
:config (setq-default
;; Use case found instead of adjusting case
company-dabbrev-downcase nil
;; Limit search to buffers of same mode
company-dabbrev-other-buffers t))Company-dictionary
(use-package company-dict
:demand t
:after company
:config
;; Where to look for dictionary files. Default is ~/.emacs.d/dict
(setq company-dict-dir (concat user-emacs-directory "dict/"))
;; Optional: if you want it available everywhere
(add-to-list 'company-backends 'company-dict)
;; Optional: evil-mode users may prefer binding this to C-x C-k for vim
;; omni-completion-like dictionary completion
(define-key evil-insert-state-map (kbd "C-c TAB") 'company-dict))Auto-revert
(setq auto-revert-interval 5)
(auto-revert-set-timer)
(add-hook 'dired-mode-hook 'auto-revert-mode)Ace Window
(use-package ace-window
:demand t
:after key-chord
:init
(custom-set-faces
'(aw-leading-char-face ((t (:background "black" :foreground "white" :underline t :weight extra-bold)))))
(key-chord-define evil-normal-state-map "al" 'ace-window)
(key-chord-define evil-normal-state-map "la" 'ace-window)
:config
(setq aw-keys '(?a ?s ?d ?f ?h ?j ?k ?l)
aw-background nil
aw-dispatch-always t))Avy
(use-package avy
:demand t
:after key-chord
:config
(setq avy-keys '(?a ?s ?d ?f ?h ?j ?k ?l))
(custom-set-faces
'(avy-lead-face ((t (:background "white" :foreground "gray1"))))
'(avy-lead-face-0 ((t (:background "white" :foreground "gray3"))))
'(avy-lead-face-1 ((t (:background "white" :foreground "gray5"))))
'(avy-lead-face-2 ((t (:background "white" :foreground "gray7"))))))Bindings
(use-package which-key
:demand t
:config (which-key-mode))Centered Cursor
(use-package centered-cursor-mode
:commands centered-cursor-mode)Commenting
(use-package evil-nerd-commenter
:commands evilnc-comment-or-uncomment-lines)Dired
Add human readable and place directories at top.
(setq dired-listing-switches "-ahl --group-directories-first")Ediff
;; Ediff should not open in separate window.
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; Ediff looks better horizontally normally
(setq ediff-split-window-function 'split-window-horizontally)Editor Config
(use-package editorconfig
:config
(editorconfig-mode 1))Eshell
(use-package eshell
:ensure nil
:commands (eshell eshell-mode)
:config
(setq hfj/eshell-date-regex (rx (repeat 4 digit) "-" (repeat 2 digit) "-" (repeat 2 digit) " " (repeat 2 digit) ":" (repeat 2 digit))
eshell-prompt-regexp (concat (rx bol)
hfj/eshell-date-regex
(rx " " (regexp "[^#$\n]* [#$] ")))
eshell-prompt-function #'(lambda ()
(concat (format-time-string "%Y-%m-%d %H:%M")
" "
(abbreviate-file-name (eshell/pwd))
" " (if (= (user-uid) 0) "#" "$") " ")))
(add-hook 'eshell-mode-hook 'hfj/eshell-hook))
(use-package esh-autosuggest
:hook (eshell-mode . esh-autosuggest-mode))Expand region
https://github.com/magnars/expand-region.el
(use-package expand-region
:demand t)Flycheck
(use-package flycheck
:init
(global-flycheck-mode)
:config
(add-hook 'after-init-hook #'global-flycheck-mode)
(setf flycheck-display-errors-delay 1.0)
(setq flycheck-display-errors-function
#'flycheck-display-error-messages-unless-error-list)
(setq flycheck-navigation-minimum-level 'error))Flyspell
(defun hfj/enable-flyspell ()
(flyspell-mode 1))
(defun hfj/disable-flyspell ()
(flyspell-mode -1))
(dolist (hook '(text-mode-hook org-mode-hook))
(add-hook hook #'hfj/enable-flyspell))
(dolist (hook '(change-log-mode-hook log-edit-mode-hook))
(add-hook hook #'hfj/disable-flyspell))
(add-hook 'prog-mode-hook 'flyspell-prog-mode)Garbage collection
(add-hook 'focus-out-hook #'garbage-collect)Geiser
(use-package geiser
:commands (run-geiser)
:init
(setq geiser-repl-use-other-window nil
geiser-default-implementation 'racket))GPG
(require 'auth-source)
;; This is required to get a GPG prompt
(setq epa-pinentry-mode 'loopback)Helm
Main
(use-package helm
:demand t
:config
(helm-mode 1)
(setq-default helm-split-window-in-side-p t ; open helm buffer inside current window, not occupy whole other window
helm-ff-search-library-in-sexp t ; search for library in `require' and `declare-function' sexp.
helm-scroll-amount 8 ; scroll 8 lines other window using M-<next>/M-<prior>
helm-ff-file-name-history-use-recentf t
helm-echo-input-in-header-line t)
(setq helm-candidate-number-limit 250)
(define-key helm-map (kbd "C-r") 'evil-paste-from-register))Helm Command
(use-package helm-command
:ensure nil
:after helm
:bind ([remap execute-extended-command] . helm-M-x)
:config
(setq-default helm-M-x-fuzzy-match t))Helm Files
(use-package helm-files
:ensure nil
:after helm
:bind ([remap find-file] . helm-find-files)
:config
(setq-default
helm-ff-no-preselect t
helm-ff-skip-boring-files t
helm-find-file-ignore-thing-at-point t))Helm Swoop
(use-package helm-swoop
:after helm
:commands helm-swoop
:config
(setq helm-swoop-split-direction 'split-window-horizontally))Helm Ag
(use-package helm-ag
:after helm)Highlight
(global-hi-lock-mode 1)
(setq hi-lock-file-patterns-policy #'(lambda (dummy) t))
(use-package highlight-thing
:init
(add-hook 'prog-mode-hook 'highlight-thing-mode)
:config
(setq highlight-thing-exclude-thing-under-point t
highlight-thing-case-sensitive-p t)
(setq highlight-thing-ignore-list
(append highlight-thing-ignore-list
'("*"
"**"
"***"
"****"
"*****"
"******"
"*******")))
(face-spec-set 'highlight-thing
'((t (:inherit 'hi-green-b)))))Hydra
Main
(use-package hydra
:after evil
:config
(setq-default hydra-default-hint nil))
(cl-defun hfj/dynamic-format-hydra-doc (title parts &optional (max-width 80))
(cl-labels ((do-replacements (str)
(replace-regexp-in-string (rx "%s(") "("
(replace-regexp-in-string (rx "_" (group (not (any "_"))) "_") "\\1" str)))
(get-length (part)
(let ((count 0)
(pops '()))
(cl-loop for ch across (do-replacements part)
do (cond ((and pops (= ch (car pops)))
(setq pops (cdr pops)))
((= ?_ ch)
(push ?_ pops))
((= ?( ch)
(when (null pops)
(incf count))
(push ?) pops))
((null pops)
(incf count)))
finally (return count)))))
(let* ((parts-lengths (map 'list #'get-length parts))
(output-lines '()))
(cl-labels ((try-height (height)
(let ((column-width 0)
(total-width 0)
(parts-count 0))
(dolist (part parts)
(when (= 0 (cl-rem parts-count height))
(incf total-width column-width)
(setq column-width 0))
(incf parts-count)
(setq column-width (max (get-length part) column-width)))
(incf total-width column-width)
(message "Total width: %d" total-width)
(<= total-width max-width)))
)
(let ((recommended-height (cl-loop for height from 1 below (length parts)
until(try-height height)
finally (return height)))
(lines '())
(row-width 0))
(cl-loop for n from 1 to recommended-height
do (push (string) lines))
(message "Blank lines: %s" lines)
(cl-loop for n from 0 below (length parts)
for row-n = (cl-rem n recommended-height)
do (progn
(message "Row-n: %s" row-n)
(when (= 0 row-n)
(setq row-width (cl-loop for i from 0 below recommended-height
while (< (+ i n) (length parts))
maximizing (length (elt parts (+ i n)))))
(message "Row-width: %s" row-width)
)
(setf (elt lines row-n)
(format "%s%s%s "
(elt lines row-n)
(elt parts n)
(make-string (- row-width (length (elt parts n))) ? )))
(message "Lines now: %s" lines))
finally (return (format "%s\n%s" title (s-join "\n" lines)))))))))git-gutter
(defun hfj/gg-stat ()
(let ((s (git-gutter:statistic)))
(format "Added %d lines, Deleted %d lines" (car s) (cdr s))))
(defhydra hydra-git-gutter (:hint nil)
"
Git gutter %s(hfj/gg-stat)
^Navigation^ ^Actions^ ^Actions^
^-^---------------^-^-------------^-^------
_n_: next _s_: stage _m_: mark
_p_: previous _R_: revert
"
("q" nil)
("n" hfj/git-gutter-next-hunk)
("p" hfj/git-gutter-prev-hunk)
("s" git-gutter:stage-hunk)
("m" git-gutter:mark-hunk)
("R" git-gutter:revert-hunk))
outline
(defhydra hydra-outline ()
"Outline"
("q" nil)
("<tab>" outline-cycle "cycle")
("<backtab>" outshine-cycle-buffer "cycle all")
("j" outline-next-visible-heading)
("k" outline-previous-visible-heading)
("gj" outline-forward-same-level)
("gk" outline-backward-same-level)
("h" outline-up-heading)
("l" outline-next-heading)
("K" outline-move-subtree-up)
("J" outline-move-subtree-down)
("L" outline-demote)
("H" outline-promote)
("n" outshine-narrow-to-subtree "narrow")
("w" widen "widen"))persp-mode
(defmacro hfj/make-tab (name &rest body)
"Select an existing tab, or create one and configure it."
`(cond
((persp-with-name-exists-p ,name)
(persp-switch ,name))
(t
(persp-switch ,name)
,@body)))
(defun hfj/make-tab-f (name setup-actions)
"Select an existing tab, or create one and configure it."
(cond
((persp-with-name-exists-p name)
(persp-switch name))
(t
(persp-switch name)
(funcall setup-actions))))
(defun define-layout-inner (name f)
"Add layout config to hfj/predefined-layouts"
(setq hfj/predefined-layouts
(delete-if #'(lambda (a) (string-equal (car a) name))
hfj/predefined-layouts))
(push (list* name (cons name f)) hfj/predefined-layouts)
(setq hfj/predefined-layouts
(sort hfj/predefined-layouts
#'(lambda (a b) (string< (car a) (car b))))))
(defmacro hfj/define-layout (name &rest body)
"Add layout config to hfj/predefined-layouts"
`(define-layout-inner ,name #'(lambda () ,@body)))
(defun hfj/pick-layout ()
"Switch to a new or existing layout."
(interactive)
(let* ((names (persp-names))
(name (completing-read "Switch to layout: " names))
(exists (persp-with-name-exists-p name)))
(persp-switch name)
(unless exists
(switch-to-buffer "*scratch*"))))
(defvar hfj/predefined-layouts '())
(defun hfj/pick-predefined-layout ()
"Create a predefined layout to be selectable from list."
(interactive)
(when (null hfj/predefined-layouts)
(error "No layouts configured."))
(let ((layout-name-and-actions (helm :sources (helm-build-sync-source "layout"
:candidates hfj/predefined-layouts))))
(when layout-name-and-actions
(hfj/make-tab-f (car layout-name-and-actions) (cdr layout-name-and-actions)))))
(defun hfj/persp-kill-current ()
(interactive)
(let ((persp (get-current-persp)))
(cond ((null persp) (error "Unable to kill default layout."))
(t (persp-kill (persp-name persp))))))
(defun hfj/persp-switch-to-n (n)
(let ((names (persp-names-current-frame-fast-ordered))
(count 1))
(dolist (name names)
(when (= count n)
(persp-switch name))
(cl-incf count))))
(defun hfj/persp-switch-to-1 () (interactive) (hfj/persp-switch-to-n 1))
(defun hfj/persp-switch-to-2 () (interactive) (hfj/persp-switch-to-n 2))
(defun hfj/persp-switch-to-3 () (interactive) (hfj/persp-switch-to-n 3))
(defun hfj/persp-switch-to-4 () (interactive) (hfj/persp-switch-to-n 4))
(defun hfj/persp-switch-to-5 () (interactive) (hfj/persp-switch-to-n 5))
(defun hfj/persp-switch-to-6 () (interactive) (hfj/persp-switch-to-n 6))
(defun hfj/persp-switch-to-7 () (interactive) (hfj/persp-switch-to-n 7))
(defun hfj/persp-switch-to-8 () (interactive) (hfj/persp-switch-to-n 8))
(defun hfj/persp-switch-to-9 () (interactive) (hfj/persp-switch-to-n 9))
(defun hfj/persp-switch-to-10 () (interactive) (hfj/persp-switch-to-n 10))
(defun hydra-perse-names ()
(let ((names (persp-names-current-frame-fast-ordered))
(current-name (safe-persp-name (get-current-persp)))
(parts '())
(count 1))
(dolist (name names (s-join " | " (nreverse parts)))
(cond ((eq name current-name)
(push (format "[%d:%s]" count name) parts))
(t
(push (format "%d:%s" count name) parts)))
(cl-incf count))))
(defhydra hydra-persp (:hint nil)
"
Layouts %s(hydra-perse-names)
^Navigation^ ^Selection^ ^Actions^ ^Buffers^
^-^---------------^-^---------------^-^--------------^-^------------
_n_: next _l_: choose _d_: delete _a_: add buffer
_p_: previous _L_: predefined _r_: rename
"
("q" nil)
("a" persp-add-buffer :exit t)
("d" hfj/persp-kill-current)
("l" hfj/pick-layout :exit t)
("L" hfj/pick-predefined-layout :exit t)
("r" persp-rename :exit t)
("n" persp-next)
("p" persp-prev)
("1" hfj/persp-switch-to-1 :exit t)
("2" hfj/persp-switch-to-2 :exit t)
("3" hfj/persp-switch-to-3 :exit t)
("4" hfj/persp-switch-to-4 :exit t)
("5" hfj/persp-switch-to-5 :exit t)
("6" hfj/persp-switch-to-6 :exit t)
("7" hfj/persp-switch-to-7 :exit t)
("8" hfj/persp-switch-to-8 :exit t)
("9" hfj/persp-switch-to-9 :exit t)
("0" hfj/persp-switch-to-10 :exit t))smartparens
(defhydra hydra-smartparens ()
"Smartparens"
("q" nil)
;; Wrapping
("(" (lambda (_) (interactive "P") (sp-wrap-with-pair "(")))
("{" (lambda (_) (interactive "P") (sp-wrap-with-pair "{")))
("'" (lambda (_) (interactive "P") (sp-wrap-with-pair "'")))
("\"" (lambda (_) (interactive "P") (sp-wrap-with-pair "\"")))
("w" (lambda (_) (interactive "P") (sp-wrap-with-pair "(")) "wrap")
("W" sp-unwrap-sexp)
;; Movement
("l" sp-next-sexp)
("h" sp-backward-sexp)
("j" sp-down-sexp)
("k" sp-backward-up-sexp)
("L" sp-forward-symbol)
("H" sp-backward-symbol)
("^" sp-beginning-of-sexp)
("$" sp-end-of-sexp)
("t" sp-transpose-sexp "transpose")
("u" undo-tree-undo "undo")
("y" sp-copy-sexp "copy")
("d" sp-kill-sexp "delete")
("s" sp-forward-slurp-sexp "slurp")
("S" sp-backward-slurp-sexp)
("b" sp-forward-barf-sexp "barf")
("B" sp-backward-barf-sexp)
("v" sp-select-next-thing "select")
("V" sp-select-previous-thing))flycheck-errors
(defhydra flycheck-errors ()
"Flycheck"
("q" nil)
;; Wrapping
("n" flycheck-next-error "next error")
("p" flycheck-previous-error "previous error"))IBuffer
(setq ibuffer-saved-filter-groups
'(("HFJ"
("org" (mode . org-mode))
("slime" (or
(name . "^\\*inferior-lisp")
(name . "^\\*slime-")))
("programming"
(or (derived-mode . prog-mode)
(mode . ess-mode)
(mode . compilation-mode)))
("text document"
(and (derived-mode . text-mode)
(not (starred-name))))
("web"
(or (derived-mode . sgml-mode)
(derived-mode . css-mode)
(mode . javascript-mode)
(mode . js2-mode)
(mode . scss-mode)
(derived-mode . haml-mode)
(mode . sass-mode)))
("dired" (mode . dired-mode))
("planner" (or
(name . "^\\*Calendar\\*$")
(name . "^diary$")))
("magit" (name . "^magit[-:]")))))
(defun hfj/ibuffer-mode-hook ()
(ibuffer-auto-mode 1)
(ibuffer-switch-to-saved-filter-groups "HFJ")
(add-to-list 'ibuffer-never-show-predicates "^\\*helm")
;; Use human readable Size column instead of original one
(define-ibuffer-column size-h
(:name "Size" :inline t)
(let ((bs (buffer-size)))
(cond
((> bs 1000000) (format "%7.1fM" (/ bs 1000000.0)))
((> bs 100000) (format "%7.0fk" (/ bs 1000.0)))
((> bs 1000) (format "%7.1fk" (/ bs 1000.0)))
(t (format "%8d" bs)))))
;; Show persp mode layout name
(define-ibuffer-column persp
(:name "Tab" :inline t)
(let* ((p (persp--buffer-in-persps (current-buffer))))
(if (null p)
""
(persp-name (car p)))))
;; Modify the default ibuffer-formats
(setq ibuffer-formats
'((mark modified read-only " "
(name 18 18 :left :elide)
" "
(size-h 9 -1 :right)
" "
(mode 16 16 :left :elide)
" "
(persp 10 10 :left :elide)
" "
filename-and-process))))
(add-hook 'ibuffer-mode-hook 'hfj/ibuffer-mode-hook)Indentation
(use-package aggressive-indent
:commands aggressive-indent-mode)Itail
(use-package itail
:commands itail)Key chords
(use-package key-chord
:demand t
:after evil
:config
(key-chord-mode 1))Layouts (persp-mode)
(use-package persp-mode
:demand t
:config
(setq persp-auto-resume-time -1 ;; No autoload buffers
persp-set-last-persp-for-new-frames nil
persp-reset-windows-on-nil-window-conf t
persp-autokill-buffer-on-remove t
persp-add-buffer-on-after-change-major-mode t
persp-kill-foreign-buffer-behaviour 'kill)
(persp-mode 1)
;; (define-key evil-normal-state-map (kbd "gt") 'persp-next)
;; (define-key evil-normal-state-map (kbd "gT") 'persp-prev)
(with-eval-after-load "term"
(persp-def-auto-persp "term"
:parameters '((dont-save-to-file . t))
:mode 'term-mode
:dyn-env '(after-switch-to-buffer-functions ;; prevent recursion
(persp-add-buffer-on-find-file nil)
persp-add-buffer-on-after-change-major-mode)
:hooks '(after-switch-to-buffer-functions)
:switch 'window)))Org
(defun hfj/org-mode-hook ()
(company-mode t)
;; Incorporate local completions into company
(add-hook 'completion-at-point-functions 'pcomplete-completions-at-point nil t))
(use-package org
:mode (("\\.org$" . org-mode))
:ensure org-plus-contrib
:config
(setq org-hide-leading-stars t
org-edit-src-persistent-message nil
org-imenu-depth 6
org-startup-indented t)
(add-hook 'org-mode-hook 'hfj/org-mode-hook)
(hfj/leader-bind 'org-mode-map "o" 'org-open-at-point "open link")
(hfj/leader-bind 'org-mode-map "'" 'org-edit-special "source edit")
(hfj/leader-bind 'org-mode-map "i" 'org-indent-mode "indent")
(hfj/leader-bind 'org-mode-map "z" nil "source block")
(hfj/leader-bind 'org-mode-map "z z" 'hfj-org-mode/yank-org-src-block "copy block")
(hfj/minor-leader-bind 'org-src-mode "c" 'org-edit-src-exit "save")
(hfj/minor-leader-bind 'org-src-mode "k" 'org-edit-src-abort "cancel")
(general-define-key :states 'normal
:keymaps 'org-mode-map
"<return>" 'org-open-at-point))
;; For org html export
(use-package htmlize)
(use-package evil-org
:commands evil-org-mode
:after org
:init
(add-hook 'org-mode-hook 'evil-org-mode)
:config
(add-hook 'evil-org-mode-hook
(lambda ()
(evil-org-set-key-theme '(textobjects insert navigation additional todo heading)))))Org Agenda
(defun hfj/maybe-save-org-files ()
(save-some-buffers nil #'(lambda () (org-agenda-file-p))))
(defun hfj/org-agenda-goto ()
(interactive)
(org-agenda-goto t)
(evil-scroll-line-to-top nil))
(use-package org-agenda
:commands org-agenda
:ensure nil
:after org
:config
(require 'evil-org-agenda)
(evil-org-agenda-set-keys)
(require 'org-habit)
(setq org-habit-graph-column 54)
(require 'org-super-agenda)
(general-define-key :states 'motion
:keymaps 'org-agenda-mode-map
"<return>" 'hfj/org-agenda-goto)
(advice-add 'org-agenda-quit :before 'hfj/maybe-save-org-files)
(setq org-agenda-span 2)
(setq org-agenda-custom-commands
'(("g" "By group"
((agenda "" ((org-super-agenda-groups
'((:name "Timed" :time-grid t)
(:name "Grouped" :auto-group t)))))
(todo "" ((org-agenda-overriding-header "Projects")
(org-super-agenda-groups
'((:name none ; Disable super group header
:children todo)
(:discard (:anything t))))))))
("u" "unscheduled tasks" tags "-DEADLINE={.+}-SCHEDULED={.+}/!TODO|STARTED|WAITING"))))
(use-package org-super-agenda
:after org
:config
(org-super-agenda-mode))Org Alert
(use-package org-alert
:load-path "local-packages/org-alert/"
:after org
:commands (org-alert-check org-alert-enable)
:init
(hfj/after-config
(setq ;; org-alert-headline-regexp "\\(Sched[^:]+:[^:\n]+\\|TODO [^:!\n]+\\|Deadline:[^:\n]+\\)"
org-alert-notification-title "gtd"
org-alert-interval (* 60 20))
(org-alert-enable)))Org Bullets
(use-package org-bullets
:after org
:commands org-bullets-mode
:init
(add-hook 'org-mode-hook 'org-bullets-mode))Org Drill
(use-package org-drill
:commands (org-drill org-drill-cram org-drill-tree)
:after org
:ensure nil
:init
(hfj/leader-declare-subtree 'org-mode-map "d" "org-drill")
(hfj/leader-bind 'org-mode-map "d d" 'org-drill-tree "drill tree at point")
(hfj/leader-bind 'org-mode-map "d f" 'org-drill "drill file")
(hfj/leader-bind 'org-mode-map "d c" 'org-drill-cram "cram")
(hfj/leader-bind 'org-mode-map "d r" 'org-drill-resume "resume")
(hfj/leader-declare-subtree 'org-mode-map "d a" "add")
(hfj/leader-bind 'org-mode-map "d a q" 'hfj/drill-add-q-and-a "Q/A")
(hfj/leader-bind 'org-mode-map "d a 2" 'hfj/drill-add-two-sided "2 sided")
(hfj/leader-bind 'org-mode-map "d a c" 'hfj/drill-add-cloze "cloze")
(hfj/leader-bind 'org-mode-map "d a m" 'hfj/drill-add-multi-sided "multi sided"))
(defun hfj/drill-add-q-and-a ()
"Add a question and answer org-drill as subheading of current section."
(interactive)
;; Add new subheading
(move-end-of-line nil)
(org-insert-subheading nil)
(save-excursion
(insert "Q/A-Card")
(org-set-tags-to (list "drill"))
(org-set-tags nil t) ;; Align tag
(move-end-of-line nil)
(insert "\nTODO: question\n")
;; Add answer subheading
(move-end-of-line nil)
(org-insert-subheading nil)
(insert "The Answer")
(insert "\nTODO: answer")))
(defun hfj/drill-add-two-sided ()
"Add a two-sided org-drill as subheading of current section."
(interactive)
;; Add new subheading
(move-end-of-line nil)
(org-insert-subheading nil)
(save-excursion
(insert "Two-Sided-Card")
(org-set-tags-to (list "drill"))
(org-set-tags nil t) ;; Align tag
(move-end-of-line nil)
(insert "
:PROPERTIES:
:DRILL_CARD_TYPE: twosided
:END:
TODO: Always shown header
")
;; Add card 1
(org-insert-subheading nil)
(insert "Side-1")
(insert "\nTODO: side 1")
;; Add card 2
(org-insert-heading nil)
(insert "Side-2")
(insert "\nTODO: side 2")
;; Add notes
(org-insert-heading nil)
(insert "Notes")
(insert "\nTODO: notes and examples")
))
(defun hfj/drill-add-multi-sided ()
"Add a multi-sided org-drill as subheading of current section."
(interactive)
;; Add new subheading
(move-end-of-line nil)
(org-insert-subheading nil)
(save-excursion
(insert "Two-Sided-Card")
(org-set-tags-to (list "drill"))
(org-set-tags nil t) ;; Align tag
(move-end-of-line nil)
(insert "
:PROPERTIES:
:DRILL_CARD_TYPE: multisided
:END:
TODO: Always shown header
")
;; Add card 1
(org-insert-subheading nil)
(insert "Side-1")
(insert "\nTODO: side 1")
;; Add card 2
(org-insert-heading nil)
(insert "Side-2")
(insert "\nTODO: side 2")
;; Add card 3
(org-insert-heading nil)
(insert "Side-3")
(insert "\nTODO: side 3")))
(defun hfj/drill-add-cloze ()
"Add a multi-cloze org-drill as subheading of current section."
(interactive)
;; Add new subheading
(move-end-of-line nil)
(org-insert-subheading nil)
(save-excursion
(insert "Cloze-Card")
(org-set-tags-to (list "drill"))
(org-set-tags nil t) ;; Align tag
(move-end-of-line nil)
(insert "
:PROPERTIES:
:DRILL_CARD_TYPE: hide1cloze
:END:
Fill in [word] or [another|with hint]
")))Org inside comments (poporg)
(use-package poporg
:after org)Org Journal
(use-package org-journal
:after org
:config
(setq org-journal-dir "~/Documents/journal/"
org-journal-file-format "%Y/%Y-%m/%Y-%m-%d.org"
org-journal-date-prefix "#+TITLE: "
org-journal-date-format "%A, %B %d %Y"
org-journal-time-prefix "* "
org-journal-time-format "%R "
org-journal-find-file 'find-file))Org Web Mode
(use-package org-web-tools
:after org
:commands (org-web-tools-read-url-as-org
org-web-tools-convert-links-to-page-entries
org-web-tools-insert-link-for-url
org-web-tools-insert-web-page-as-entry))Outliner
(use-package outshine
:init
(add-hook 'outline-minor-mode-hook 'outshine-hook-function)
(add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
(setq outshine-use-speed-commands t))Parenthesis
Smartparens: Add closing braces automatically
(use-package smartparens
:commands smartparens-mode
:diminish smartparens-mode)
(use-package evil-smartparens
:commands evil-smartparens-mode
:init
(add-hook 'smartparens-enabled-hook 'evil-smartparens-mode))Rainbow delimiters
(use-package rainbow-delimiters
:commands rainbow-delimiters-mode
:init
(add-hook 'lisp-mode-hook 'rainbow-delimiters-mode)
(add-hook 'emacs-lisp-mode-hook 'rainbow-delimiters-mode))(use-package pdf-tools
:defer 1
:config
;; initialize
(pdf-tools-install)
;; open pdfs scaled to fit page
(setq-default pdf-view-display-size 'fit-page)
;; automatically annotate highlights
(setq pdf-annot-activate-created-annotations t
pdf-view-resize-factor 1.05)
(general-define-key :states 'normal
:keymaps 'pdf-view-mode-map
"o" 'pdf-outline))Proced
(setf proced-format 'long)Project Management
(use-package projectile
:demand t
:config
;; Without this, projectile spends too much time trying to figure out the mode
;; line.
(setq projectile-mode-line "Projectile")
(require 'helm-projectile)
(projectile-global-mode))
(use-package helm-projectile
:after projectile
:config
(setq projectile-enable-caching t
projectile-indexing-method 'alien))Purpose
(use-package window-purpose
:config
(purpose-mode))Recent Files
(use-package recentf
:ensure nil
:config
(recentf-mode 1)
(setq recentf-max-menu-items 100)
(run-at-time nil (* 60 60) 'recentf-save-list))S for strings
(use-package s
:demand t)Save file position
(save-place-mode 1)
;; Give up if file is no longer available
(setq save-place-forget-unreadable-files nil)Search
(use-package ag
:demand t)Scratch
(defvar hfj/open-layer-scratch-directory (concat user-emacs-directory
"/.cache/scratch"))
(defun hfj/open-layer-scratch-path (&optional layout-name)
"Determine the path for the scratch for the current layout, or the one supplied. Path will be in hfj/open-layer-scratch-directory."
(let* ((layout-name (or layout-name (safe-persp-name (get-frame-persp)) "default"))
(file-name (replace-regexp-in-string "[\\\\/ ]" "-" layout-name)))
(concat hfj/open-layer-scratch-directory
"/"
(hfj/dash-escape-file-name (downcase layout-name))
".org")))
(defun hfj/open-layer-scratch ()
"Open a scratch pad for the current layout. Files are stored in hfj/open-layer-scratch-directory."
(interactive)
(let ((layout-name (or (safe-persp-name (get-frame-persp)) "default")))
(cond ((string= layout-name persp-nil-name)
(switch-to-buffer "*scratch*"))
(t
(let ((scratch-path (hfj/open-layer-scratch-path layout-name)))
(find-file scratch-path)
(when (= (point-min) (point-max))
(insert (concat "#+TITLE: Scratch: " (capitalize layout-name) "\n"))))))))Roku
(defun roku-key-to-command (key)
(cond ((eq key 'home) "Home")
((eq key 'reverse) "Rev")
((eq key 'forward) "Fwd")
((eq key 'play) "Play")
((eq key 'select) "Select")
((eq key 'left) "Left")
((eq key 'right) "Right")
((eq key 'down) "Down")
((eq key 'up) "Up")
((eq key 'back) "Back")
((eq key 'instant-replay) "InstantReplay")
((eq key 'info) "Info")
((eq key 'backspace) "Backspace")
((eq key 'search) "Search")
((eq key 'enter) "Enter")
(t (url-hexify-string (format "Lit_%c" key)))))
(defun roku-make-keypress-url (host key)
(concat "http://" host ":8060/keypress/" (roku-key-to-command key)))
(defun roku-callback (x)
(when x
(message "%s" x)))
(defun roku-send-keypress (host key)
(let ((url-request-method "POST")
(url-request-data ""))
(url-retrieve (roku-make-keypress-url host key) #'roku-callback)))
;;; Tied to host
(defvar roku-current-host nil)
(defun roku-run (host)
"Initiate transient state."
(setq roku-current-host host)
(hydra-roku/body))
(defmacro roku-make-command (command)
`(defun ,(intern (concat "roku-current-send-" (symbol-name command))) ()
(interactive)
(roku-send-keypress roku-current-host ',command)))
(roku-make-command back)
(roku-make-command home)
(roku-make-command info)
(roku-make-command instant-replay)
(roku-make-command play)
(roku-make-command search)
(roku-make-command select)
(roku-make-command backspace)
(roku-make-command enter)
(roku-make-command forward)
(roku-make-command reverse)
(roku-make-command up)
(roku-make-command down)
(roku-make-command left)
(roku-make-command right)
(defun roku-send-text-sender (str-to-send pos)
(let ((url-request-method "POST")
(url-request-data ""))
(cond ((< pos (length str-to-send))
(let ((url (roku-make-keypress-url roku-current-host (elt str-to-send pos))))
(url-retrieve url
#'(lambda (status)
(roku-send-text-sender str-to-send (1+ pos))))))
(t
(roku-current-send-enter)))))
(defun roku-send-text ()
(interactive)
(let ((s (read-string "Send text: ")))
(when (stringp s)
(message "%s" s)
(roku-send-text-sender s 0))
t))
(defhydra hydra-roku (:hint nil)
"
[_h_] left [_j_] down [_k_] up [_l_] right
[_<return>_] ok [_SPC_] play [_gh_] home [_<backspace>_] backspace
[_H_] back [_i_] info [_m_] instant replay [_s_] search
[_,_] reverse [_._] forward [_t_] enter text [_q_] quit"
("q" nil)
("h" roku-current-send-left)
("l" roku-current-send-right)
("j" roku-current-send-down)
("k" roku-current-send-up)
("<backspace>" roku-current-send-backspace)
("H" roku-current-send-back)
("<return>" roku-current-send-select)
("SPC" roku-current-send-play)
("gh" roku-current-send-home)
("i" roku-current-send-info)
("m" roku-current-send-instant-replay)
("s" roku-current-send-search)
("," roku-current-send-reverse)
("." roku-current-send-forward)
("t" roku-send-text))Text
(defun hfj/text-mode-hook ()
)
(add-hook 'text-mode-hook 'hfj/text-mode-hook)Tilde Fringe
(use-package vi-tilde-fringe
:demand t
:config
(global-vi-tilde-fringe-mode))Toggles Hydra
(defun hfj/y-n (val)
(if val "y" "n"))
(defun hfj/toggle-line-numbers ()
(interactive)
(cond ((version< emacs-version "26") nil)
((or (not (boundp 'display-line-numbers))
(null display-line-numbers))
(display-line-numbers-mode))
((eq display-line-numbers t)
(setq display-line-numbers 'relative))
((eq display-line-numbers 'relative)
(setq display-line-numbers 'visual))
(t
(setq display-line-numbers nil))))
(defun hfj/toggle-super-sub-words ()
(interactive)
(cond (subword-mode
(subword-mode 0)
(superword-mode 1))
(superword-mode
(subword-mode 0)
(superword-mode 0))
(t
(subword-mode 1))))
(defun hfj/org-alert-timer-enabled-p ()
(let ((has-timer nil))
(dolist (timer timer-list)
(when (eq (elt timer 5) 'org-alert-check)
(setq has-timer t)))
has-timer))
(defun hfj/toggle-org-alert ()
(interactive)
(if (hfj/org-alert-timer-enabled-p)
(org-alert-disable)
(org-alert-enable)))
(defvar hfj/hydra-toggles
`((?a "_a_ autofill %s(hfj/ht ?a)"
,#'(lambda () (hfj/y-n auto-fill-function)))
(?c "_c_ centered %s(hfj/ht ?c)"
,#'(lambda () (hfj/y-n (and (boundp 'centered-cursor-mode) centered-cursor-mode))))
(?i "_i_ icase search %s(hfj/ht ?i)"
,#'(lambda () (hfj/y-n case-fold-search)))
(?I "_I_ agressive indent %s(hfj/ht ?I)"
,#'(lambda () (hfj/y-n aggressive-indent-mode)))
(?n "_n_ line-numbers %s(hfj/ht ?n)"
,#'(lambda () (cond ((version< emacs-version "26") nil)
((or (not (boundp 'display-line-numbers))
(null display-line-numbers))
"n")
((eq display-line-numbers t)
"a")
((eq display-line-numbers 'relative)
"r")
(t
"v"))))
(?o "_o_ org-alert %s(hfj/ht ?o)"
,#'(lambda () (hfj/y-n (hfj/org-alert-timer-enabled-p))))
(?s "_s_ sup/sub words %s(hfj/ht ?s)"
,#'(lambda () (cond (subword-mode "-")
(superword-mode "+")
(t "n"))))
(?t "_t_ truncate-lines %s(hfj/ht ?t)"
,#'(lambda () (hfj/y-n truncate-lines)))
(?T "_T_ toggle-tabs %s(hfj/ht ?T)"
,#'(lambda () (hfj/y-n indent-tabs-mode)))
(?w "_w_ wrap-lines %s(hfj/ht ?w)"
,#'(lambda () (hfj/y-n word-wrap)))
(?W "_W_ whitespace %s(hfj/ht ?W)"
,#'(lambda () (hfj/y-n (cond ((local-variable-p 'whitespace-mode)
whitespace-mode)
(t
global-whitespace-mode)))))))
(defun hfj/ht (key)
(let ((row (assoc key hfj/hydra-toggles)))
(when row
(funcall (elt row 2)))))
(defun hfj/toggle-case-fold-search ()
(interactive)
(setq case-fold-search (not case-fold-search)))
(defun hfj/toggle-whitespace-mode ()
(interactive)
(cond ((local-variable-p 'whitespace-mode)
(whitespace-mode (if whitespace-mode 0 1)))
(t
(whitespace-mode (if global-whitespace-mode 0 1)))))
(defun hfj/toggle-toggle-tabs ()
(interactive)
(setq-local indent-tabs-mode (not indent-tabs-mode)))
(defhydra hydra-toggles (:hint nil)
(format "%s" (hfj/dynamic-format-hydra-doc "Toggles"
(map 'list #'(lambda (row) (elt row 1)) hfj/hydra-toggles)))
("a" auto-fill-mode)
("c" centered-cursor-mode)
("i" hfj/toggle-case-fold-search)
("I" aggressive-indent-mode)
("n" hfj/toggle-line-numbers)
("o" hfj/toggle-org-alert)
("s" hfj/toggle-super-sub-words)
("t" toggle-truncate-lines)
("T" hfj/toggle-toggle-tabs)
("w" visual-line-mode)
("W" hfj/toggle-whitespace-mode)
("q" nil))Tramp
(let ((cache-seconds (* 60 60 4)))
(setq
;; Disable version control
vc-ignore-dir-regexp (format "\\(%s\\)\\|\\(%s\\)" vc-ignore-dir-regexp tramp-file-name-regexp)
;; May be faster than default scp
tramp-default-method "ssh"
;; Don't invalidate cache quickly
remote-file-name-inhibit-cache cache-seconds
;; speed up completions
tramp-completion-reread-directory-timeout cache-seconds
;; How long to cache entered passwords
password-cache-expiry 900))Undo
(use-package undo-tree
:config
(global-undo-tree-mode -1))Version Control
Magit
(use-package magit
:commands (magit-status)
:config
(require 'evil-magit)
(setq magit-ediff-dwim-show-on-hunks t))
(use-package evil-magit)Git gutter
(use-package git-gutter
:commands (git-gutter-mode git-gutter:previous-hunk git-gutter:next-hunk)
:init
(add-hook 'org-mode-hook 'git-gutter-mode)
(add-hook 'prog-mode-hook 'git-gutter-mode)
:diminish git-gutter-mode)
(defun hfj/git-gutter-prev-hunk (arg)
(interactive "p")
(git-gutter:previous-hunk arg)
(evil-scroll-line-to-center nil))
(defun hfj/git-gutter-next-hunk (arg)
(interactive "p")
(git-gutter:next-hunk arg)
(evil-scroll-line-to-center nil))vc-msg
(use-package vc-msg
:commands (vc-msg-show))Wiki
(defun hfj/helm-multidir-select-org-file (dirs helm-name)
"Use helm to select a single org file from among a list of directories."
(let (results)
(map nil
(lambda (dir-item)
(let (dirpath description)
(cond ((stringp dir-item) (setf dirpath dir-item))
((consp dir-item) (setf dirpath (cdr dir-item) description (car dir-item)))
(t (error "Unknown dir item type: %s" dir-item)))
(map nil
(lambda (filepath)
(let* ((filename (substring (file-name-nondirectory filepath) 0 -4))
(name (cond ((stringp description) (format "%s (%s)" filename description))
(t filename))))
(push (cons name filepath) results)))
(directory-files dirpath t "^[a-zA-Z0-9].*\.org$"))))
dirs)
(setq results (sort results (lambda (a b) (string< (car a) (car b)))))
(helm :sources (helm-build-sync-source helm-name
:candidates results))))
(defun hfj/helm-multidir-find-org-file (dirs helm-name)
(interactive)
(let ((selected-filepath (hfj/helm-multidir-select-org-file dirs helm-name)))
(when selected-filepath
(find-file selected-filepath))))Windows
Buffer Alist
(defun hfj/buffer-mode (buffer-or-name)
(with-current-buffer buffer-or-name major-mode))
(defun hfj/make-mode-matcher (mode)
#'(lambda (buffer-name action)
(let ((result (eql mode (hfj/buffer-mode buffer-name))))
;; (message "Result of %s: %s" buffer-name result)
result)))
(add-to-list 'display-buffer-alist
`(,(rx bos "*Flycheck errors*" eos)
display-buffer-in-side-window
(side . bottom)
(slot . 1)
(window-height . 12)
(preserve-size . (nil . t))
(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t)))))
(add-to-list 'display-buffer-alist
`(,(rx bos "*Flycheck error messages*" eos)
display-buffer-in-side-window
(side . bottom)
(slot . -1)
(window-height . 12)
(preserve-size . (nil . t))
(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t)))))
(add-to-list 'display-buffer-alist
`(,(rx bos "*Warnings*" eos)
display-buffer-in-side-window
(side . top)
(slot . 0)
(window-height . fit-window-to-buffer)
(preserve-size . (nil . t))
(window-parameters . ((no-other-window . t)
(no-delete-other-windows . t)))))
(add-to-list 'display-buffer-alist
`(,(rx bos "magit: ")
(display-buffer-reuse-window display-buffer-in-previous-window display-buffer-same-window)))
(add-to-list 'display-buffer-alist
`(,(rx bos "magit-revision: ")
(display-buffer-same-window)))
(add-to-list 'display-buffer-alist
`(,(rx bos "*slime-scratch*")
(display-buffer-reuse-window display-buffer-same-window)))
(add-to-list 'display-buffer-alist
`(,(rx bos "*slime-repl")
(display-buffer-reuse-window display-buffer-same-window)))
;; (defun hfj/match-dired-on-non-dired (buffer-name action)
;; (and (eq 'dired-mode (hfj/buffer-mode buffer-name))
;; (not (eq 'dired-mode major-mode))))
;; ;; Dired to popup
;; (add-to-list 'display-buffer-alist
;; '(hfj/match-dired-on-non-dired
;; (display-buffer-pop-up-window display-buffer-in-side-window)
;; (side . bottom)))Set height by selection
(defun hfj/set-window-height-to-region (pos1 pos2)
"Take the selected region and resize the current window to it."
(interactive "r")
(set-window-text-height nil (count-lines pos1 pos2))
(deactivate-mark t)
(setf (point) pos1)
(evil-scroll-line-to-top nil))Swap buffers by direction
(use-package buffer-move
:defer 1
:commands (buf-move-left buf-move-right buf-move-up buf-move-down))Toggle window dedicated
(defun hfj/toggle-window-dedicated ()
"Dedicate the current buffer to the current window."
(interactive)
(let* ((window (get-buffer-window (current-buffer)))
(initially-dedicated (window-dedicated-p window)))
(set-window-dedicated-p window (not initially-dedicated))
(if initially-dedicated
(message "Window dedication removed")
(message "Window dedication set"))))Indirect buffers
(defun hfj/clone-indirect-buffer-here ()
"Create an indirect buffer at the current window, cloning the current buffer."
(interactive)
(let* ((prefix "View:")
(real-buffer-name (replace-regexp-in-string "<[0-9]+>" "" (s-chop-prefix prefix (buffer-name))))
(window-to-use (selected-window))
(buf (make-indirect-buffer real-buffer-name
(generate-new-buffer-name (concat prefix real-buffer-name))
t)))
(set-window-buffer window-to-use buf)))Undo window changes
(use-package winner
:demand t
:config (winner-mode 1))Whitespace
(setq whitespace-style
'(face
tabs
;; spaces ; highlight spaces
trailing ; highlight spaces at end of line(should be eliminated on save)
;; lines ; Highlight long lines
;; lines-tail ; Highlight long lines only after the column
space-before-tab
newline
indentation
;; empty
space-after-tab
;; space-mark ; Place . in every space
tab-mark ; Show all TABs
;; newline-mark ; $ at end of line
))
(setq whitespace-display-mappings
'((space-mark 32 [183] [46]) ; normal space
(space-mark 160 [164] [95])
(space-mark 2208 [2212] [95])
(space-mark 2336 [2340] [95])
(space-mark 3616 [3620] [95])
(space-mark 3872 [3876] [95])
(newline-mark 10 [182 10]) ; newlne
(tab-mark 9 [9655 9] [92 9]) ; tab
))
(add-hook 'after-init-hook (lambda ()
(global-whitespace-mode 1)))YASnippet
(defvar smartparens-mode-original-value)
(defun disable-sp-hippie-advice (&rest _)
(setq smartparens-mode-original-value smartparens-mode)
(setq smartparens-mode nil)
t) ; We should still return t.
;; This advice could be added to other functions that usually insert
;; balanced parens, like `try-expand-list'.
(advice-add 'yas-hippie-try-expand :after-while #'disable-sp-hippie-advice)
(defun reenable-sp-hippie-advice (&rest _)
(when (boundp 'smartparens-mode-original-value)
(setq smartparens-mode smartparens-mode-original-value)
(makunbound 'smartparens-mode-original-value)))
(use-package yasnippet
:demand t
:config
(yas-global-mode 1)
(require 'hippie-exp)
(setq hippie-expand-try-functions-list
(cons 'yas-hippie-try-expand hippie-expand-try-functions-list))
(define-key yas-minor-mode-map (kbd "<tab>") nil)
(define-key yas-minor-mode-map (kbd "TAB") nil)
;; (define-key yas-minor-mode-map (kbd "<the new key>") yas-maybe-expand) ; use hippie
;;keys for navigation
(define-key yas-keymap [(tab)] nil)
(define-key yas-keymap (kbd "TAB") nil)
(define-key yas-keymap [(shift tab)] nil)
(define-key yas-keymap [backtab] nil)
(define-key yas-keymap (kbd "M-n") 'yas-next-field)
(define-key yas-keymap (kbd "M-p") 'yas-prev-field)
(advice-add 'hippie-expand :after #'reenable-sp-hippie-advice
;; Set negative depth to make sure we go after
;; `sp-auto-complete-advice'.
'((depth . -100))))
Bindings
Common
(define-key evil-insert-state-map (kbd "M-/") 'hippie-expand)
(hfj/spc-bind hfj/main-leader-key 'execute-extended-command "elisp cmd")
(key-chord-define evil-normal-state-map "op" 'helm-show-kill-ring)
(defun hfj/word-search (&optional backwards)
(interactive)
(er/mark-symbol)
(let* ((forward (not backwards))
(str (buffer-substring (region-beginning) (region-end)))
(str-quoted (regexp-quote str))
(re-str (concat (if (string= "w" (string (char-syntax (elt str 0))))
"\\b"
"")
str-quoted
(if (string= "w" (string (char-syntax (elt str (1- (length str))))))
"\\b"
""))))
(deactivate-mark t)
(setq isearch-forward forward)
(setq evil-regexp-search t)
(push re-str regexp-search-ring)
(evil-search re-str forward t)))
(defun hfj/word-search-backwards ()
(interactive)
(hfj/word-search t))
(define-key evil-normal-state-map (kbd "*") 'hfj/word-search)
(define-key evil-normal-state-map (kbd "#") 'hfj/word-search-backwards)
(define-key evil-motion-state-map (kbd "zf") 'reposition-window)
(define-key evil-motion-state-map (kbd "<f1>")
#'(lambda ()
(interactive)
(org-agenda nil "g")
(delete-other-windows)
(let ((first-window (get-buffer-window)))
(split-window-right)
(org-agenda-redo)
(windmove-right)
(if (< 0 (length org-agenda-files))
(find-file (car org-agenda-files))
(switch-to-buffer "*scratch*"))
(select-window first-window))))
(define-key evil-motion-state-map (kbd "<f2>")
#'(lambda ()
(interactive)
(org-agenda nil "u")
(delete-other-windows)
(let ((first-window (get-buffer-window)))
(split-window-right)
(org-agenda-redo)
(windmove-right)
(if (< 0 (length org-agenda-files))
(find-file (car org-agenda-files))
(switch-to-buffer "*scratch*"))
(select-window first-window))))applications: SPC a
(hfj/spc-declare-subtree "a" "applications")
(hfj/spc-bind "a a" 'annotate-annotate "annotate")
(hfj/spc-bind "a A" #'(lambda ()
(interactive)
(unless (and (boundp 'annotate-mode)
annotate-mode)
(annotate-mode)))
"load annotations")
(hfj/spc-bind "a u" 'undo-tree-visualize "undo")
(hfj/spc-bind "a t" 'hfj/message-at-time "timer")
(hfj/spc-bind "a d" 'dired "dired")
(hfj/spc-bind "a p" 'proced "proced")
(hfj/spc-declare-subtree "a s" "shell")
(hfj/spc-bind "a s e" 'hfj/switch-to-eshell "eshell")
(hfj/spc-bind "a s E" 'hfj/eshell-here "new eshell here")
(hfj/spc-bind "a s s" 'hfj/switch-to-shell "shell")
(hfj/spc-bind "a s t" 'hfj/ansi-term-here "term")
(hfj/spc-declare-subtree "a r" "radio")
(hfj/spc-bind "a r c"
(hfj/make-link-player "http://hpm.streamguys1.com/classical-aac.m3u")
"houston classical")wiki: SPC a w
(add-hook 'hfj/post-config-hook
#'(lambda ()
(when (and (boundp 'hfj/wiki-dirs)
(listp hfj/wiki-dirs))
(defun hfj/pick-wiki-file ()
(interactive)
(hfj/helm-multidir-find-org-file hfj/wiki-dirs "wiki"))
(defun hfj/pick-wiki-dir ()
(interactive)
(let ((selection (helm :sources (helm-build-sync-source "wiki dir"
:candidates hfj/wiki-dirs))))
(when selection
(dired selection))))
(defun hfj/search-wiki ()
(interactive)
(let ((just-dirs (map 'list
#'(lambda (x)
(cond ((stringp x) x)
((and (consp x) (stringp (cdr x))) (cdr x))))
hfj/wiki-dirs)))
(with-helm-default-directory (car just-dirs)
(helm-do-ag nil just-dirs))))
(hfj/spc-declare-subtree "a w" "wiki")
(hfj/spc-bind "a w w" 'hfj/pick-wiki-file "find file")
(hfj/spc-bind "a w d" 'hfj/pick-wiki-dir "dired")
(hfj/spc-bind "a w a" 'hfj/search-wiki "search"))))buffers: SPC b
(hfj/spc-declare-subtree "b" "buffers")
(hfj/spc-bind "b b" #'(lambda () (interactive) (helm-mini)) "buffers")
(defun hfj/delete-buffer ()
"Delete current buffer without breaking layout"
(interactive)
(cond ((null (window-prev-buffers))
(evil-delete-buffer (current-buffer)))
(t
(let ((window-to-use (selected-window))
(config (current-window-configuration))
(prev-buffer (save-excursion (previous-buffer))))
(unwind-protect
(kill-buffer (current-buffer))
(set-window-configuration config))
(set-window-buffer window-to-use prev-buffer)))))
(hfj/spc-bind "b d" 'hfj/delete-buffer "delete")
(defun hfj/slime-scratch ()
"Create and switch to slime scratch."
(interactive)
(let* ((name "*slime-scratch*")
(buf (get-buffer name)))
(cond ((null buf)
(save-window-excursion
(slime-scratch))
(pop-to-buffer name))
(t
(pop-to-buffer name)))))
(hfj/spc-bind "b l" 'hfj/slime-scratch "cl-scratch")
(hfj/spc-bind "b L" 'slime-repl "cl-repl")
(hfj/spc-bind "b i" #'ibuffer "ibuffer")
(hfj/spc-bind "b n" 'switch-to-next-buffer "next buffer")
(hfj/spc-bind "b p" 'switch-to-prev-buffer "prev buffer")
(hfj/spc-bind "b TAB" 'evil-switch-to-windows-last-buffer "last buffer")
(hfj/spc-bind "b s"
#'(lambda ()
(interactive)
(switch-to-buffer "*scratch*"))
"scratch")
(hfj/spc-bind "b S"
#'(lambda ()
(interactive)
(switch-to-buffer "*scratch*")
(delete-other-windows))
"only scratch")converting: SPC c
(hfj/spc-declare-subtree "c" "convert")
(hfj/spc-bind "c s" 'hfj/point-seconds-to-date "seconds->date")commenting: SPC ;
(hfj/spc-bind ";" 'evilnc-comment-or-uncomment-lines "comment")errors: SPC e
(hfj/spc-declare-subtree "e" "errors")
(hfj/spc-bind "e l" 'flycheck-list-errors "list errors")
(hfj/spc-bind "e n" #'(lambda () (interactive) (flycheck-next-error) (flycheck-errors/body)) "next error")
(hfj/spc-bind "e p" #'(lambda () (interactive) (flycheck-previous-error) (flycheck-errors/body)) "previous error")files: SPC f
(hfj/spc-declare-subtree "f" "file")
(hfj/spc-bind "f f" 'find-file "find file")
(hfj/spc-bind "f s" 'save-buffer "save")
(hfj/spc-bind "f S" 'save-some-buffers "save all")
(hfj/spc-bind "f b" 'helm-bookmarks "bookmarks")
(hfj/spc-bind "f y" 'hfj/show-and-copy-buffer-filename "copy filename")
(hfj/spc-bind "f Y" 'hfj/show-and-copy-buffer-filename-and-line "copy filename and line")
(hfj/spc-declare-subtree "f e" "edit")
(hfj/spc-bind "f e d"
#'(lambda ()
(interactive)
(find-file (expand-file-name "dotemacs.org"
user-emacs-directory)))
"dotemacs.org")
(hfj/spc-bind "f e l"
#'(lambda ()
(interactive)
(find-file (expand-file-name "locals.org"
user-emacs-directory)))
"dotemacs.org")git: SPC g
(hfj/spc-declare-subtree "g" "git")
(hfj/spc-bind "g b" 'magit-blame "blame")
(hfj/spc-bind "g s" 'magit-status "status")
(hfj/spc-bind "g g" 'hydra-git-gutter/body "gutter")
(hfj/spc-bind "g m" 'vc-msg-show "message")
(hfj/spc-bind "g n"
#'(lambda (arg)
(interactive "p")
(hfj/git-gutter-next-hunk arg)
(hydra-git-gutter/body))
' "next hunk")
(hfj/spc-bind "g p"
#'(lambda (arg)
(interactive "p")
(hfj/git-gutter-prev-hunk arg)
(hydra-git-gutter/body))
' "prev hunk")
(hfj/spc-declare-subtree "g f" "file")
(hfj/spc-bind "g f h" 'magit-log-buffer-file "history")help: SPC h
(hfj/spc-declare-subtree "h" "help")
(hfj/spc-declare-subtree "h d" "describe")
(hfj/spc-bind "h h" 'helm-apropos "symbol")
(hfj/spc-bind "h d b" 'describe-bindings "bindings")
(hfj/spc-bind "h d f" 'describe-function "function")
(hfj/spc-bind "h d k" 'describe-key "key")
(hfj/spc-bind "h d m" 'describe-mode "mode")
(hfj/spc-bind "h d t" 'describe-theme "theme")
(hfj/spc-bind "h d v" 'describe-variable "variable")
(hfj/spc-bind "h i" 'info "info")jumps: SPC j
(hfj/spc-declare-subtree "j" "jumps")
(hfj/spc-bind "j l"
#'(lambda (&optional arg)
(interactive "p")
(let ((avy-all-windows nil))
(evil-avy-goto-line arg)))
"jump to line")
(hfj/spc-bind "j p" 'avy-pop-mark "pop mark")
(hfj/spc-bind "j j" 'evil-avy-goto-char-timer "goto char")layouts: SPC l
(hfj/spc-bind "l" 'hydra-persp/body "layouts")narrow/number: SPC n
(hfj/spc-declare-subtree "n" "narrow/number")
(hfj/spc-bind "n f" 'narrow-to-defun "function")
(hfj/spc-bind "n n" 'widen "widen")
(hfj/spc-bind "n p" 'narrow-to-page "page")
(hfj/spc-bind "n r" 'narrow-to-region "region")
(hfj/spc-bind "n w" 'widen "widen")
(hfj/spc-bind "n +" 'evil-numbers/inc-at-pt "number+")
(hfj/spc-bind "n -" 'evil-numbers/dec-at-pt "number-")
(hfj/spc-bind-on-major 'org-mode-map "n b" 'org-narrow-to-block "org block")
(hfj/spc-bind-on-major 'org-mode-map "n e" 'org-narrow-to-element "org element")
(hfj/spc-bind-on-major 'org-mode-map "n s" 'org-narrow-to-subtree "org subtree")org: SPC o
(hfj/spc-declare-subtree "o" "org")
(hfj/spc-declare-subtree "o a" "org agenda")
(hfj/spc-bind "o a a" 'org-agenda "agenda")
(hfj/spc-bind "o a g"
#'(lambda ()
(interactive)
(org-agenda nil "g"))
"by group")
(hfj/spc-declare-subtree "o C" "org clock")
(hfj/spc-bind "o C o" 'org-clock-clock-out "clock out")
(hfj/spc-bind "o C c" 'org-clock-clock-cancel "clock cancel")
(hfj/spc-bind "o C C" 'org-clock-goto "clock goto")
(hfj/spc-bind "o l" 'org-store-link "store link")
(hfj/spc-bind "o L" 'org-insert-link "insert link")
(hfj/spc-bind "o j j" 'org-journal-new-entry "new entry")
(hfj/spc-bind "o j p" 'org-journal-previous-entry "previous entry")
(hfj/spc-bind "o j n" 'org-journal-next-entry "next entry")
(hfj/spc-bind "o p" 'poporg-dwim "poporg")
(hfj/spc-bind "o <tab>" 'org-cycle "cycle")outline: SPC O
(hfj/spc-bind "O"
#'(lambda ()
(interactive)
(unless outline-minor-mode
(outline-minor-mode))
(hydra-outline/body))
"outline")project: SPC p
(require 'projectile)
(require 'helm-projectile)
(hfj/spc-declare-subtree "p" "projectile")
(hfj/spc-bind "p p" 'helm-projectile-switch-project "switch project")
(hfj/spc-bind "p f" 'helm-projectile-find-file "find file")
(hfj/spc-bind "p d" 'helm-projectile-find-dir "find dir")
(hfj/spc-bind "p I" 'projectile-invalidate-cache "invalidate cache")
(hfj/spc-bind "p r" 'projectile-replace "replace")
(hfj/spc-bind "p R" 'projectile-replace-regexp "replace regex")quit: SPC q
(hfj/spc-declare-subtree "q" "quit")
(defun hfj/non-server-quit ()
(interactive)
(cond (multiple-frames (delete-frame))
(t (save-buffers-kill-emacs))))
(cond ((daemonp)
(hfj/spc-bind "q q" 'delete-frame "kill frame"))
(t
(hfj/spc-bind "q q" 'hfj/non-server-quit "quit")))
(hfj/spc-bind "q Q" 'save-buffers-kill-emacs "quit all")search: SPC /
(defun hfj/quick-search ()
(interactive)
(cond ((ignore-errors (projectile-project-root))
(helm-do-ag (projectile-project-root)))
((project-current)
(helm-do-ag-project-root))
(buffer-file-name
(helm-do-ag (file-name-directory buffer-file-name)))
(t
(helm-do-ag))))
(defun hfj/quick-search-wap ()
(interactive)
(er/mark-symbol)
(hfj/quick-search))
(hfj/spc-bind "/" 'hfj/quick-search "quick search")
(hfj/spc-bind "*" 'hfj/quick-search-wap "quick search wap")search: SPC s
(hfj/spc-declare-subtree "s" "search")
(hfj/spc-bind "s j" 'helm-semantic-or-imenu "imenu")
(defun hfj/helm-imenu-comments ()
"Imenu display comments."
(interactive)
(let* ((imenu-create-index-function 'evilnc-imenu-create-index-function))
(helm-imenu)))
(hfj/spc-bind "s c" 'hfj/helm-imenu-comments "imenu comments")
(defun hfj/swoop-search ()
(interactive)
(er/mark-symbol)
(let* ((forward t)
(regex-p nil)
(str (buffer-substring (region-beginning) (region-end))))
(evil-push-search-history str forward)
(setq evil-regexp-search regex-p)
(setq isearch-string str)
(isearch-update-ring str regex-p))
(helm-swoop))
(hfj/spc-bind "s s" 'hfj/swoop-search "swoop")
(hfj/spc-bind "s f" 'helm-do-ag "search from dir")
(hfj/spc-bind "s l" 'helm-resume "resume")search/highlight: SPC s h
(hfj/spc-declare-subtree "s h" "highlight")
(hfj/spc-bind "s h h"
#'(lambda ()
(interactive)
(if global-highlight-thing-mode
(progn
(global-highlight-thing-mode 0)
;; Set prefix to force face selection
(let ((current-prefix-arg t))
(highlight-symbol-at-point))
(global-highlight-thing-mode 1))
;; Set prefix to force face selection
(let ((current-prefix-arg t))
(highlight-symbol-at-point))))
"highlight symbol")
(hfj/spc-bind "s h l" 'highlight-lines-matching-regexp "lines by regex")
(hfj/spc-bind "s h p" 'highlight-phrase "phrase")
(hfj/spc-bind "s h r" 'highlight-regexp "regex")
(hfj/spc-bind "s h u" 'unhighlight-regexp "unhighlight regex")
(hfj/spc-bind "s h w" 'hi-lock-write-interactive-patterns "write interactive patterns")
(hfj/spc-bind "s h f" 'hi-lock-find-patterns "find patterns")select: SPC v
(hfj/spc-bind "v" 'er/expand-region "expand select")smartparens: SPC k
(hfj/spc-bind "k" 'hydra-smartparens/body "smartparens")text: SPC x
(hfj/spc-declare-subtree "x" "text")
(hfj/spc-declare-subtree "x r" "replace")
(hfj/spc-bind "x r w" 'hfj/replace-word-at-point "replace word")
(hfj/spc-bind "x r s" 'hfj/replace-symbol-at-point "replace symbol")
(hfj/spc-bind "x w" 'whitespace-cleanup "clean whitespace")toggles: SPC t
(hfj/spc-bind "t" 'hydra-toggles/body "toggles")universal argument: SPC u
(defun hfj/inc-uni-arg (arg)
(interactive "P")
(cond ((null arg)
(universal-argument))
(t
(universal-argument-more arg))))
(hfj/spc-bind "u" 'hfj/inc-uni-arg "uni-arg")windows: SPC w
(hfj/spc-declare-subtree "w" "windows")
(hfj/spc-bind "w h" 'evil-window-left "jump left")
(hfj/spc-bind "w l" 'evil-window-right "jump right")
(hfj/spc-bind "w j" 'evil-window-down "jump down")
(hfj/spc-bind "w k" 'evil-window-up "jump up")
(hfj/spc-bind "w H" 'buf-move-left "swap left")
(hfj/spc-bind "w L" 'buf-move-right "swap right")
(hfj/spc-bind "w J" 'buf-move-down "swap down")
(hfj/spc-bind "w K" 'buf-move-up "swap up")
(hfj/spc-bind "w s" 'evil-window-split "h-split")
(hfj/spc-bind "w v" 'evil-window-vsplit "v- split")
(hfj/spc-bind "w d" 'delete-window "close")
(hfj/spc-bind "w u" 'winner-undo "undo")
(hfj/spc-bind "w m" 'delete-other-windows "maximize")
(hfj/spc-bind "w w" 'ace-window "jump")
(hfj/spc-bind "w W" 'ace-swap-window "swap")
(hfj/spc-bind "w t" 'hfj/toggle-window-dedicated "dedicate")
(hfj/spc-bind "w f" 'fit-window-to-buffer "fit window")
(hfj/spc-bind "w i" 'hfj/clone-indirect-buffer-here "clone indirect")Post hooks
(run-hooks 'hfj/post-config-hook)