This package emulates surround.vim by Tim Pope. The functionality is wrapped into a minor mode.
This package uses Evil as its vi layer.
To enable it through use-package, add the following lines to ~/.emacs
or ~/.emacs.d/init.el
:
(use-package evil-surround
:ensure t
:config
(global-evil-surround-mode 1))
Alternatively, can add the evil-surround.el
file to your load-path and add (require 'evil-surround)
to your init file.
Also, Instead of enabling it globally, you can also enable surround-mode
along a major mode by adding turn-on-surround-mode
to the mode hook.
You can surround in visual-state with S<textobject>
or gS<textobject>
.
Or in normal-state with ys<textobject>
or yS<textobject>
.
You can change a surrounding with cs<old-textobject><new-textobject>
.
You can delete a surrounding with ds<textobject>
.
A surround pair is this (trigger char with textual left and right strings):
(?> . ("<" . ">"))
or this (trigger char and calling a function):
(?< . surround-read-tag)
You can add new by adding them to evil-surround-pairs-alist
.
For more information do: C-h v evil-surround-pairs-alist
.
evil-surround-pairs-alist
is a buffer local variable, which means that
you can have different surround pairs in different modes. By default <
is used to insert a tag, in C++ this may not be useful - but inserting
angle brackets is, so you can add this:
(add-hook 'c++-mode-hook (lambda ()
(push '(?< . ("< " . " >")) evil-surround-pairs-alist)))
Don’t worry about having two entries for <
surround will take the
first.
Or in Emacs Lisp modes using ` to enter ` ’ is quite useful, but not
adding a pair of ` (the default behavior if no entry in
evil-surround-pairs-alist
is present), so you can do this:
(add-hook 'emacs-lisp-mode-hook (lambda ()
(push '(?` . ("`" . "'")) evil-surround-pairs-alist)))
without affecting your Markdown surround pairs, where the default is useful.
To change the default evil-surround-pairs-alist
you have to use setq-default
,
for example to remove all default pairs:
(setq-default evil-surround-pairs-alist '())
or to add a pair that surrounds with two ` if you enter ~:
(setq-default evil-surround-pairs-alist
(push '(?~ . ("``" . "``")) evil-surround-pairs-alist))
- You can create new evil objects that will be respected by evil-surround. Just use the following code:
;; this macro was copied from here: https://stackoverflow.com/a/22418983/4921402
(defmacro define-and-bind-quoted-text-object (name key start-regex end-regex)
(let ((inner-name (make-symbol (concat "evil-inner-" name)))
(outer-name (make-symbol (concat "evil-a-" name))))
`(progn
(evil-define-text-object ,inner-name (count &optional beg end type)
(evil-select-paren ,start-regex ,end-regex beg end type count nil))
(evil-define-text-object ,outer-name (count &optional beg end type)
(evil-select-paren ,start-regex ,end-regex beg end type count t))
(define-key evil-inner-text-objects-map ,key #',inner-name)
(define-key evil-outer-text-objects-map ,key #',outer-name))))
(define-and-bind-quoted-text-object "pipe" "|" "|" "|")
(define-and-bind-quoted-text-object "slash" "/" "/" "/")
(define-and-bind-quoted-text-object "dollar" "*" "*" "*")
(define-and-bind-quoted-text-object "dollar" "$" "\\$" "\\$") ;; sometimes your have to escape the regex
You can add support for new operators by adding them to evil-surround-operator-alist
.
For more information do: C-h v evil-surround-operator-alist
.
By default, surround works with evil-change
and evil-delete
.
To add support for the evil-paredit package,
you need to add evil-paredit-change
and evil-paredit-delete
to evil-surround-operator-alist
, like so:
(add-to-list 'evil-surround-operator-alist
'(evil-paredit-change . change))
(add-to-list 'evil-surround-operator-alist
'(evil-paredit-delete . delete))
Here are some usage examples (taken from surround.vim):
Press cs"'
inside
"Hello world!"
to change it to
'Hello world!'
Now press cs'<q>
to change it to
<q>Hello world!</q>
To go full circle, press cst"
to get
"Hello world!"
To remove the delimiters entirely, press ds"
.
Hello world!
Now with the cursor on “Hello”, press ysiw]
(iw
is a text object).
[Hello] world!
Let’s make that braces and add some space (use }
instead of {
for no
space): cs]{
{ Hello } world!
Now wrap the entire line in parentheses with yssb
or yss)
.
({ Hello } world!)
Revert to the original text: ds{ds)
Hello world!
Emphasize hello: ysiw<em>
<em>Hello</em> world!
Finally, let’s try out visual mode. Press a capital V (for linewise
visual mode) followed by S<p class
“important”>=.
<p class="important">
<em>Hello</em> world!
</p>
Suppose you want to call a function on your visual selection or a text
object. You can simply press f
instead of the aforementioned keys and
are then prompted for a functionname in the minibuffer, like with the
tags. So with:
"Hello world!"
… after selecting the string, then pressing Sf
, entering print
and
pressing return you would get
print("Hello world!")
This is due to an upstream change in vim-surround
. It happened in this commit. See the
discussion in this pull request for more details.
- you are encouraged to test your changes a standard environment with a clean emacs and just the needed plugins
# open a shell and go to the evil-surround directory, after cloning it
make
make emacs
# now load evil-surround/test/evil-surround-test.el and M-x ert and run the tests
# open a shell and go to the evil-surround directory, after cloning it
make
make test
Credits and many thanks go to Tim Harper, the original mantainer of the package.
GNU General Public License v3
Copyright (C) 2010 - 2017 Tim Harper
Copyright (c) 2018 - 2019 The evil-surround Contributors