evil-cleverparens is modal-editing optimized for editing Lisp. It works under the following principles:
Act like Vim/evil where useful, but prevent actions that would throw the order of your parentheses and other delimiters into question.
Make the most out of the combination of structural and modal editing.
Provide but don't force additional features on the user.
The recommended way to install is via
elpa from MELPA. The following should work:
evil-cleverparens uses functions from both
paredit. Neither one is required by default, but using one of them is highly recommended, as
evil-cleverparens doesn't provide anything for the
insert-state. If you are an user of
smartparens-strict-mode is also recommended.
evil-cleverparens with your favorite lispy-mode use:
(add-hook '<your-lispy-mode> #'evil-cleverparens-mode)
If you are using
nil (the defaults), I would recommend putting
(setq evil-move-beyond-eol t) in your config so that certain movement commands don't break at the end of the lines (see issue #29 for details).
evil-smartparens includes evil text-objects for forms, comments and defuns. Since these may be useful in non-lisp-like modes, they have been separated out into their own file and can be used with:
in which case you need to give them key-bindings on your own.
When used with
evil-cleverparens we have:
Form bound to
Form is a pair-delimited range as defined by
smartparens for your major-mode. It's much like if you combined
evil-(a|inner)-(paren|bracket|curly|double-quote) under a single text-object.
Comment bound to
Selecting an outer comment means selecting both the comment delimiter and the comment text, whereas selecting an inner comment means selecting only the text but not the comment delimiters.
Defun bound to
Selects the top-level form.
Part of embracing Lisp and structural editing is learning to love the parentheses. Vim/evil is optimized for moving around by units of text, but for friends of Lisp the parentheses are more than just text. Therefore in addition to the regular evil movement keys, the following set of commands are provided:
||Move backward by sexp|
||Move forward by sexp|
||Move to the beginning of a top-level form|
||Move to the end of the top-level form|
||Move backward up a sexp.|
||Move forward up a sexp.|
||Move to the previous opening parentheses|
||Move to the next closing parentheses|
||Move to the next opening parentheses|
||Move to the previous closing parentheses|
To customize them see
evil-cleverparens-use-additional-movement-keys to enable/disable them and
evil-cp-additional-movement-keys for the keys.
Besides parentheses, the other logical unit of structural movement are symbols. Unfortunately the regular Vim/evil movement keys (
gE) complect this idea by not making a distinction between symbols and delimiters. This distinction is made for you when using the
evil-cp-(forward|backward)-(word|symbol)-(begin|end) commands, which happily skip past all parentheses and other delimiters.
TODO: Moving by word's by skipping delimiters doesn't work yet.
If you prefer the vanilla Vim way, set
There's also an option to swap the
word behavior of these keys controlled by:
Yank / Delete / Change
When it comes to yanking (in the Vim sense) unbalanced expressions, there are two ways to handle this:
- Ignore the extra parentheses of the yanked region and only store the safe parts.
- Store everything and fill in the missing delimiters in kill-ring.
evil-cleverparens supports both of these approaches, where the former is called ignoring and the latter balancing behavior. This defaults to ignoring and can be toggled with
M-T. The current behavior is indicated in the modeline via
ecp/i for ignoring and
ecp/b for balancing.
Because checking and fixing the safety of a region can be computationally expensive, there is a variable
evil-cleverparens-threshold (defaults to 1500) that controls upto how many characters will be checked before giving up and defaulting the normal
evil behavior. In practice this is rarely a problem but it is something worth being aware of. This feature is adopted from evil-smartparens.
If for some reason
evil-cleverparens messes up, or you would just like to torture your program for unspecified reasons, you can skip the protective measures by prepending next command with
- Should work pretty much as you would expect!
ccwill leave the point to indentation or to the last unmatched opening delimiter of the line.
t) controls if the surrounding form should be indented after deleting or changing.
- On safe lines the behavior is identical to
- On lines with unmatched opening delimiters, the range of the operation extends all the way to the end of those forms, spanning multiple lines.
- On lines with unmatched closing delimiters, the range of operation extends from point to the end-of-line.
- These act from point to the end of the current or next sexp similar to how
- Calling them at the end of a form will act on the whole form.
- Calling them with the
universal-argumentaffects everything from point until the end of the current surrounding form.
- Similar to the their little cousins, but act on the enclosing form, and in the case of
changewill also perform whitespace clean-up after themselves.
- Numeric argument increases the enclosing form up by a level.
- Using a single
universal-argumentdeletes the top-level form and its surrounding newlines.
Other Vim Related Features
sis identical to
evil's, but skips over delimiters.
Sis the same as
Cbut always starts from the beginning of the line and skips over any unmatched delimiters.
t) controls whether s and S will be overridden as described above. If you decide to set this to
nil, do it before loading
x deletes and splices
xkey works the same way it does in
evil, but when called on opening or closing delimiters of a form, it will delete both delimiters.
evildo the same thing, i.e. bring the point to the first non-blank column,
_to bring the point to the first non-blank non-opening instead.
iin a situation where the point is between a round opening parentheses and a symbol,
evil-cleverparenswill automatically insert a space and then move the cursor back for you. The rationale is that when you are in this situation, it's much more likely that you are inserting a new word at the beginning of the list rather than modifying the beginning of the current head of the list, and therefore it would be nice if the two words were already separated so that your auto-completion mode can do its thing. This behavior can be disabled by setting
evil-cp-insert-at-end-of-formare analogous to the
A, but instead of working on lines, they bring the cursor to the beginning/end of the current surrounding sexp while entering
In the same manner,
evil-cp-open-above-formare analogous to
O, again working on forms instead of lines.
Most of the following functionality is controlled by the
evil-cleverparens-use-additional-bindings setting. The keys can be customized by editing
evil-cp-additional-bindings (needs to be re-initialized).
Dragging / Transposing
In addition to regular transpose, bound to
evil-cleverparens provides additional means of moving sexps around with behavior inspired by the drag-stuff-el mode.
evil-drag-forward bound to
evil-drag-backward bound to
M-k attempt to drag the thing under point forward or backward. The depth of the thing being moved never changes, i.e. dragging is distinct from slurping or barfing.
The thing can be many different things depending on the location of the cursor:
- On top of a symbol acts on that symbol.
- Inside or on the delimiters of a form moves the form.
- If a symbol or a form can't be moved any further, the command acts on its surrounding form.
- Outside a form on a safe line will move the line.
- On a top-level comment will move the entire comment-block.
The behavior of the command with respect to top-level sexps and lines can be customized with
nil). You can also choose not to treat connected commented lines as singular units by setting
Slurping and Barfing
evil-cleverparens implements slurping and barfing both forwards and backwards using only the
> keys by making them act differently when on top of a form delimiter:
- On an opening delimiter
<will slurp backwards as many times as there are preceding opening delimiters.
- On a closing delimiter
<will barf forwards. If the form contains only a single sexp inside it then
evil-cleverparenswill question your intention and instead do nothing. Perhaps you meant to splice or delete instead?
- On a opening delimiter
>will barf backwards with the same caveat as above.
- On a closing delimiter
>will slurp forwards as many times as there are closing delimiters behind.
- When inside a form
<will barf and
>will slurp forwards.
While the specifics of the dragging, slurping and barfing behavior may seem complicated when spelled out, a lot of thought has been put to make their use feel intuitive and fluid.
evil-cleverparens editing operations work well with evil-surround, the following specialized wrapping commands are also provided:
||Wrap the next sexp in round parentheses.|
||Wrap the previous sexp in round parentheses.|
||Wrap the next sexp in square brackets.|
||Wrap the previous sexp in square brackets.|
||Wrap the next sexp in curly braces.|
||Wrap the previous sexp in curly braces.|
Each command can take a numeric argument to determine how many sexps to operate on maxing out at the number of sexps from the cursor until the end of the surrounding form. When called with the
universal-argument, the operations act on the surrounding form instead. The universal argument can be called multiple times, where each consecutive call will wrap an additional expression from the surrounding form.
Copy and Paste
evil-cp-evil-copy-paste-form will copy the surrounding form and insert it below with the proper indentation. If called outside a form it will do the same with the current line instead (as long as its safe). This command can be called with a numeric argument to repeat the paste operation that many times. Calling it with the
universal-argument will copy-paste the current top-level form and insert newlines between them.
The following commands have been lifted straight from
M-R bound to
evil-cp-raise-form acts like
sp-raise-sexp but on the enclosing form instead of the next one.
Notes and Tips
Some of the commands in
evil-cleverparens optionally accept the
C-u in vanilla Emacs), which is not bound by default in
evil and has no equivalent in Vim. If you wish to use these features, you must bind it to a key, but that alone only allows you to invoke it once, because calling
universal-argument enables a transient keymap that assumes that you are using
C-u for the next invocation. You can therefore use e.g.
<my-key> C-u C-u to invoke it three times, or you can bind your own key like this:
(define-key universal-argument-map (kbd <my-key>) 'universal-argument-more)
evil-cleverparens relies on
smartparens to identify forms where the opening delimiter contains a prefix, such as quoted lists or the anonymous function literals in Clojure. If you are having problems with such prefixed forms, make sure that the variable
sp-sexp-prefix is correctly configured for the mode you are using.
Using highlight-parentheses.el to highlight three of the closest delimiters from the location of the point with fixed colors makes it very easy to quickly identify the range of many of the operations of
evil-cleverparens is not the first Emacs/evil mode that tries to make structural editing of lisp-like languages easier. You might enjoy checking out the following modes as well:
Very rich in features but doesn't attempt to conform to the
Prevents the user from messing up their parentheses by erroring out.
evil-cleverparens originally started out as a fork of this project, with the goal of doing something useful instead of throwing an error in situations where it would make sense.
As the name suggests, this project creates an additional state for editing lisp in
Had I known of this project when starting out I would have just contributed to it instead of writing a lot of the same functionality on my own, but by the time I discovered it I had already so much code in place that I decided to continue with my own version. Some of the code in
evil-cleverparens is lifted directly from here, and the modes work roughly the same.
evil-cleverparens has more features and opinions, and probably more bugs :).