Table of Contents
- 1. Vimify Lispy as much as possible.
- 2. Make Lispy the primary state.
- 3. Make insertion vs. structure editing explicit.
- 4. No knowledge of vanilla Lispy required.
- A quick recap on structural editing for the uninitiated
- Keybindings
- Operating on regions
YAE-Lispy is Yet-Another-Evil Lispy variant that aims to make Lispy familiar and intuitive to the Vim user while retaining the full power of Lispy's structural editing capabilities.
YAE-Lispy differs from it's peers (see lispyville and sp3ctum/evil-lispy) in the following goals:
YAE-Lispy leverages the Vimmer's muscle memory and minimizes the need to learn/use Emacs binding with lispy, and thus provides a complete overhaul of Lispy's keybindings. The keybindings are closely aligned to Vim's Visual state, while differing where sensible. In addition to rebinding keys to more familiar positions, YAE-Lispy includes some primitive operators to the keymapping that vanilla Lispy intended to be accessed via. the Emacs bindings.
In contrast to other evil-flavored lispy variants, which provide support for a hybrid Lispy/Normal state approach, dipping into the featureset of Lispy while remaining in the comfort of Normal state. YAE-Lispy opts for a different approach, intending for users to primarily use Lispy state while allowing for transient forays into Normal state.
The key n will drop the user into Normal state, and will be sent back to Lispy state under the following conditions:
- An edit is made to the buffer in normal mode.
- Insert mode is exited.
The main intended usecase is to modify single symbols. The YAE-Lisper can perform a quick operation on a symbol, and get dropped right back into the Lispy state on completion.
YAE-Lispy uses the Vimmer's familiar Insert state instead of implicitly dispatching based on point location, as vanilla Lispy and evil-lispy does. One large benefit to this is that the SPC key is now freed to operate as a leader key. (*cough* doom/spacemacs *cough*) Insert mode is entered with i (unsurprisingly).
Lispy is an incredibly powerful tool, but along with it's power comes great complexity -- the following sections serve to give a short and sweet overview of Lispy's capabilities from the context of YAE-Lispy's modifications that users with no experience with Lispy/Paredit/Structural Editing can hit the ground running with.
While most text editors operate on a character level, in Lispy state we operate via the tree structure of the program itself, which conveniently maps to the sexp structure.
For example, consider the venerable append
function.
(defun append (x y)
(cond
((not x) y)
(t (cons (car x) (append (cdr x) y)))))
Here is the same function represented as a tree, where s
marks a node on the
tree.
┌─────┬───s───┬────────────┐
│ │ │ │
│ │ ┌─s─┐ ┌─────s─────────────┐
▼ ▼ │ │ ▼ │ │
defun append │ │ cond │ │
│ │ │ ┌───────s────────────────┐
▼ ▼ │ ▼ │ │
x y │ cons │ │
┌───s───┐ ┌───s───┐ ┌─────s─────┐
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │ ▼
│ y car x append │ y
┌──s──┐ ┌───s───┐
│ │ │ │
│ │ │ │
▼ ▼ ▼ ▼
not x cdr x
We can see that leaves correspond to symbols, while the nodes correspond to lists.
- Parent: The node above the current.
- Sibling:
First off, here are the keybindings in YAE-Lispy that map very closely to Vim's bindings.
key | description | demonstration |
---|---|---|
h | move to the previous list. | |
k | move to the previous list inside the current, if it exists. | |
j | move to the next list at the current level. | |
f | move to the next list. | |
d | delete the current list (and then jump to the next list). | |
c | delete the current list (and then enter insert mode). | |
p | paste before the current list. | |
y | yank the list at point. | |
u | undo. | |
i | enter insert mode. | |
a | enter insert mode. |
FOO
key | command |
---|---|
h | lispy-backward |
A lot of Lispy commands come in pairs - one reverses the other:
key | command | key | command |
---|---|---|---|
j | lispy-down |
k | lispy-up |
s | lispy-move-down |
w | lispy-move-up |
> | lispy-slurp |
< | lispy-barf |
c | lispy-clone |
C-d or DEL | |
C | lispy-convolute |
C | reverses itself |
d | lispy-different |
d | reverses itself |
M-j | lispy-split |
+ | lispy-join |
O | lispy-oneline |
M | lispy-multiline |
S | lispy-stringify |
C-u " | lispy-quotes |
; | lispy-comment |
C-u ; | lispy-comment |
xi | lispy-to-ifs |
xc | lispy-to-cond |
x> | lispy-toggle-thread-last |
x> | reverses itself |
These commands handle whitespace in addition to inserting the expected thing.
key | command |
---|---|
SPC | lispy-space |
: | lispy-colon |
^ | lispy-hat |
C-m | lispy-newline-and-indent |
Most special commands will leave the point special after they're
done. This allows to chain them as well as apply them
continuously by holding the key. Some useful hold-able keys are
jkf<>cws;.
Not so useful, but fun is /: start it from |(
position and hold
until all your Lisp code is turned into Python :).
key | command |
---|---|
q | lispy-ace-paren |
Q | lispy-ace-char |
a | lispy-ace-symbol |
H | lispy-ace-symbol-replace |
- | lispy-ace-subword |
q - lispy-ace-paren
jumps to a "(" character within current
top-level form (e.g. defun
). It's much faster than typing in the
avy
binding + selecting "(", and there's less candidates,
since they're limited to the current top-level form.
a - lispy-ace-symbol
will let you select which symbol to
mark within current form. This can be followed up with e.g. eval,
describe, follow, raise etc. Or you can simply m to
deactivate the mark and edit from there.
- - lispy-ace-subword
is a niche command for a neat combo. Start with:
(buffer-substring-no-properties
(region-beginning)|)
Type c, -, b and C-d to get:
(buffer-substring-no-properties
(region-beginning)
(region-|))
Fill end
to finish the statement.
Sometimes the expression that you want to operate on isn't bounded by parens. In that case you can mark it with a region and operate on that.
While in special:
- Mark a sexp with m -
lispy-mark-list
- Mark a symbol within sexp a -
lispy-ace-symbol
.
While not in special:
- C-SPC -
set-mark-command
- mark a symbol at point with M-m -
lispy-mark-symbol
- mark containing expression (list or string or comment) with C-M-, -
lispy-mark
The arrow keys j/k will move the region up/down within the current list. The actual code will not be changed.
Use d - lispy-different
to switch between different sides
of the region. The side is important since the grow/shrink operations
apply to current side of the region.
Use a combination of:
- > -
lispy-slurp
- extend by one sexp from the current side. Use digit argument to extend by several sexps. - < -
lispy-barf
- shrink by one sexp from the current side. Use digit argument to shrink by several sexps.
The other two arrow keys will mark the parent list of the current region:
- h -
lispy-left
- mark the parent list with the point on the left - l -
lispy-right
- mark the parent list with the point on the right
To do the reverse of the previous operation, i.e. to mark the first
child of marked list, use i - lispy-tab
.
- m -
lispy-mark-list
- deactivate region - c -
lispy-clone
- clone region and keep it active - s -
lispy-move-down
- move region one sexp down - w -
lispy-move-up
- move region one sexp up - u -
lispy-undo
- deactivate region and undo - t -
lispy-teleport
- move region inside the sexp you select withlispy-ace-paren
- C -
lispy-convolute
- exchange the order of application of two sexps that contain region - n -
lispy-new-copy
- copy region as kill without deactivating the mark - P -
lispy-paste
- replace region with current kill
- Jump to closest left paren
- Enter insert mode
- Enter insert mode if point is not special