As these two packages make Emacs Lisp programming much nicer.
8 KiB
Emacs Lisp Configuration
A literate programming file for configuring Emacs for Lisp programming.
Introduction
While I program in a lot of languages, I seem to be writing all my helper tools and scripts in … Emacs Lisp. So I’m cranking this up to 11.
New, non-literal source code comes from emacs-lisp-mode template:
(ha-auto-insert-file (rx ".el" eol) "emacs-lisp-mode.el")
Syntax Display
Dim those Parenthesis
The paren-face project lowers the color level of parenthesis which I find better.
(use-package paren-face
:hook (emacs-lisp-mode . paren-face-mode))
Show code examples with the elisp-demos package. This is really helpful.
(use-package elisp-demos
:config
(advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1))
Navigation and Editing
Goto Definitions
F’s elisp-def project does a better job at jumping to the definition of a symbol at the point, so:
(use-package elisp-def
:hook (emacs-lisp-mode . elisp-def-mode))
This should work with evil-goto-defintion, as that calls this list from evil-goto-definition-functions:
- evil-goto-definition-imenu
- evil-goto-definition-semantic
- evil-goto-definition-xref … and here is where this package will be called
- evil-goto-definition-search
I love packages that add functionality but I don’t have to learn anything.
Clever Parenthesis
We need to make sure we keep the smartparens project always in strict mode, because who wants to worry about paren-matching:
(use-package smartparens
:custom
(smartparens-global-strict-mode t)
:hook
(prog-mode . smartparens-strict-mode))
The evil-cleverparens solves having me create keybindings to the smartparens project by updating the evil states with Lisp-specific bindings.
(use-package evil-cleverparens
:after smartparens
:custom
(evil-cleverparens-use-additional-bindings t)
(evil-cleverparens-use-additional-movement-keys t)
(evil-cleverparens-use-s-and-S t)
:init
(require 'evil-cleverparens-text-objects)
:hook
(prog-mode . evil-cleverparens-mode)) ;; All the languages!
;; Otherwise: (emacs-lisp-mode . evil-cleverparens-mode)
The trick to being effective with the paredit-family of extensions is learning the keys. The killer “app” is the slurp/barf sequence. Use the <
key, in normal mode, to barf (or jettison)… in other words, move the paren closer to the point. For instance:
(+ 41 (* ‖1 3)) ⟹ (+ 41 (* ‖1) 3)
Use the >
key to slurp in outside objects into the current expression… in other words, move the paren away from the point. For instance:
(+ 41 (* ‖1) 3) ⟹ (+ 41 (* ‖1 3))
Opening Parens. Those two keys seem straight-forward, but they behave differently when the are on the opening parens.
When the point (symbolized by ‖
) is on the opening paren, <
moves the paren to the left. For instance:
(+ 41 ‖(* 1 3)) ⟹ (+ ‖(41 * 1 3))
And the >
moves the paren to the right. For instance:
(+ 41 ‖(* 1 3)) ⟹ (+ 41 * ‖(1 3))
I would like to have a list of what keybindings that work in normal
mode:
M-h
/M-l
move back/forward by functionsH
/L
move back/forward by s-expressionM-i
insert at the beginning of the formM-a
appends at the end of the formM-o
new form after the current sexpM-O
new form before the current sexpM-j
/M-k
drags thing at point and back and forth in the form>
slurp forward if at the end of form, at beginning, it barfs backwards<
slurp backward if at start of form, at the end, it barfs forwardsM-(
/M-)
wraps next/previous form in parens (braces and brackets work too)x
unwraps if the point is on the(
of an expression.D
deletes an entire s-expression, but this can depend on the position of the point.
The other advantage is moving around by s-expressions. This takes a little getting used to, for instance:
[
and]
move from paren to paren, essentially, from s-expression.H
andL
act similarly to the above.(
and)
move up to the parent s-expression
We need a real-world example. Let’s suppose we entered this:
(format "The sum of %d %d is %d" a b (+ a b))
But we forgot to define the a
and b
variables. One approach, after Escaping into the normal state, is to hit (
to just to the beginning of the s-expression, and then type, M-(
to wrap the expression, and type i
to go into insert mode:
(‖ (format "The sum of %d %d is %d" a b (+ a b)))
And now we can enter the let
expression.
Other nifty keybindings that I need to commit to muscle memory include:
M-q |
sp-indent-defun |
M-J |
sp-join-sexp |
M-s |
sp-splice-sexp |
M-S |
sp-split-sexp |
M-t |
sp-transpose-sexp |
M-v |
sp-convolute-sexp |
M-r |
sp-raise-sexp |
Eval Current Expression
A feature I enjoyed from Spacemacs is the ability to evaluate the s-expression currently containing the point. Not sure how they made it, but evil-cp-next-closing from cleverparens can help:
(defun ha-eval-current-expression ()
"Evaluates the expression the point is currently 'in'.
It does this, by jumping to the end of the current
expression (using evil-cleverparens), and evaluating what it
finds at that point."
(interactive)
(save-excursion
(evil-cp-next-closing)
(evil-cp-forward-sexp)
(call-interactively 'eval-last-sexp)))
And we just need to bind it.
(ha-prog-leader
"e c" '("current" . ha-eval-current-expression))