1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
|
[[https://user-images.githubusercontent.com/8352747/33807810-91656488-ddc3-11e7-8029-985f28471a47.png][https://user-images.githubusercontent.com/8352747/33807810-91656488-ddc3-11e7-8029-985f28471a47.png]]
[[https://travis-ci.org/emacs-evil/evil-surround.svg?branch=master][https://travis-ci.org/emacs-evil/evil-surround.svg?branch=master]]
[[https://melpa.org/#/evil-surround][https://melpa.org/packages/evil-surround-badge.svg]]
[[https://stable.melpa.org/#/evil-surround][file:https://stable.melpa.org/packages/evil-surround-badge.svg]]
[[https://www.gnu.org/licenses/gpl-3.0.en.html][https://img.shields.io/badge/license-GPLv3-blue.svg]]
This package emulates [[https://github.com/tpope/vim-surround][surround.vim]] by [[https://github.com/tpope][Tim Pope]]. The functionality is wrapped into a minor mode.
This package uses [[https://github.com/emacs-evil/evil][Evil]] as its vi layer.
* Installation
To enable it through [[https://github.com/jwiegley/use-package][use-package]], add the following lines to =~/.emacs= or =~/.emacs.d/init.el=:
#+BEGIN_SRC emacs-lisp
(use-package evil-surround
:ensure t
:config
(global-evil-surround-mode 1))
#+END_SRC
Alternatively, a user 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.
* Usage
** Add surrounding
You can surround in visual-state with =S<textobject>= or =gS<textobject>=.
Or in normal-state with =ys<textobject>= or =yS<textobject>=.
** Change surrounding
You can change a surrounding with =cs<old-textobject><new-textobject>=.
** Delete surrounding
You can delete a surrounding with =ds<textobject>=.
** Add new surround pairs
A surround pair is this (trigger char with textual left and right
strings):
#+BEGIN_SRC emacs-lisp
(?> . ("<" . ">"))
#+END_SRC
or this (trigger char and calling a function):
#+BEGIN_SRC emacs-lisp
(?< . surround-read-tag)
#+END_SRC
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:
#+BEGIN_SRC emacs-lisp
(add-hook 'c++-mode-hook (lambda ()
(push '(?< . ("< " . " >")) evil-surround-pairs-alist)))
#+END_SRC
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:
#+BEGIN_SRC emacs-lisp
(add-hook 'emacs-lisp-mode-hook (lambda ()
(push '(?` . ("`" . "'")) evil-surround-pairs-alist)))
#+END_SRC
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:
#+BEGIN_SRC emacs-lisp
(setq-default evil-surround-pairs-alist '())
#+END_SRC
or to add a pair that surrounds with two ` if you enter ~:
#+BEGIN_SRC emacs-lisp
(setq-default evil-surround-pairs-alist
(push '(?~ . ("``" . "``")) evil-surround-pairs-alist))
#+END_SRC
** Add new surround pairs through creation of evil objects
You can create new evil objects that will be respected by evil-surround. Just use the following code:
#+BEGIN_SRC emacs-lisp
;; 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 "asterisk" "*" "*" "*")
(define-and-bind-quoted-text-object "dollar" "$" "\\$" "\\$") ;; sometimes your have to escape the regex
#+END_SRC
** Add surround pairs for buffer-local text objects
Buffer-local text objects are useful for mode specific text objects that you
don't want polluting the global keymap. To make these objects work with
=evil-surround=, do the following (for example to bind pipes to =Q=):
#+BEGIN_SRC emacs-lisp
(defvar evil-some-local-inner-keymap (make-sparse-keymap)
"Inner text object test keymap")
(defvar evil-some-local-outer-keymap (make-sparse-keymap)
"Outer text object keymap")
(define-key evil-some-local-inner-keymap "Q" #'evil-inner-pipe)
(define-key evil-some-local-outer-keymap "Q" #'evil-a-pipe)
(define-key evil-visual-state-local-map "iQ" #'evil-inner-pipe)
(define-key evil-operator-state-local-map "iQ" #'evil-inner-pipe)
(define-key evil-visual-state-local-map "aQ" #'evil-a-pipe)
(define-key evil-operator-state-local-map "aQ" #'evil-a-pipe)
(setq evil-surround-local-inner-text-object-map-list (list evil-some-local-inner-keymap))
(setq evil-surround-local-outer-text-object-map-list (list evil-some-local-outer-keymap))
(setq-local evil-surround-pairs-alist (append '((?Q "|" . "|")) evil-surround-pairs-alist))
#+END_SRC
note that the binding to =evil-some-local-(inner|outer)-keymap= is purely for organizational perpouses, you can skip that step and do:
#+BEGIN_SRC emacs-lisp
(define-key evil-visual-state-local-map "iQ" #'evil-inner-pipe)
(define-key evil-operator-state-local-map "iQ" #'evil-inner-pipe)
(define-key evil-visual-state-local-map "aQ" #'evil-a-pipe)
(define-key evil-operator-state-local-map "aQ" #'evil-a-pipe)
(setq evil-surround-local-inner-text-object-map-list (list (lookup-key evil-operator-state-local-map "i")))
(setq evil-surround-local-outer-text-object-map-list (list (lookup-key evil-operator-state-local-map "a")))
(setq-local evil-surround-pairs-alist (append '((?Q "|" . "|")) evil-surround-pairs-alist))
#+END_SRC
** Add new supported operators
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:
#+BEGIN_SRC emacs-lisp
(add-to-list 'evil-surround-operator-alist
'(evil-paredit-change . change))
(add-to-list 'evil-surround-operator-alist
'(evil-paredit-delete . delete))
#+END_SRC
* Examples
Here are some usage examples (taken from [[https://github.com/tpope/vim-surround][surround.vim]]):
Press =cs"'= inside
#+BEGIN_EXAMPLE
"Hello world!"
#+END_EXAMPLE
to change it to
#+BEGIN_EXAMPLE
'Hello world!'
#+END_EXAMPLE
Now press =cs'<q>= to change it to
#+BEGIN_EXAMPLE
<q>Hello world!</q>
#+END_EXAMPLE
To go full circle, press =cst"= to get
#+BEGIN_EXAMPLE
"Hello world!"
#+END_EXAMPLE
To remove the delimiters entirely, press =ds"=.
#+BEGIN_EXAMPLE
Hello world!
#+END_EXAMPLE
Now with the cursor on "Hello", press =ysiw]= (=iw= is a text object).
#+BEGIN_EXAMPLE
[Hello] world!
#+END_EXAMPLE
Let's make that braces and add some space (use =}= instead of ={= for no
space): =cs]{=
#+BEGIN_EXAMPLE
{ Hello } world!
#+END_EXAMPLE
Now wrap the entire line in parentheses with =yssb= or =yss)=.
#+BEGIN_EXAMPLE
({ Hello } world!)
#+END_EXAMPLE
Revert to the original text: =ds{ds)=
#+BEGIN_EXAMPLE
Hello world!
#+END_EXAMPLE
Emphasize hello: =ysiw<em>=
#+BEGIN_SRC html
<em>Hello</em> world!
#+END_SRC
Finally, let's try out visual mode. Press a capital V (for linewise
visual mode) followed by =S<p class="important">=.
#+BEGIN_SRC html
<p class="important">
<em>Hello</em> world!
</p>
#+END_SRC
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:
#+BEGIN_EXAMPLE
"Hello world!"
#+END_EXAMPLE
... after selecting the string, then pressing =Sf=, entering =print= and
pressing return you would get
#+BEGIN_SRC c
print("Hello world!")
#+END_SRC
* FAAQ (frequently actually asked questions)
** Why does =vs= no longer surround?
This is due to an upstream change in =vim-surround=. It happened in this [[https://github.com/tpope/vim-surround/commit/6f0984a][commit]]. See the
discussion in [[https://github.com/timcharper/evil-surround/pull/48][this]] pull request for more details.
* Contributing
- you are encouraged to test your changes in a standard environment with a clean emacs using just the needed plugins.
** interactively
#+BEGIN_SRC sh
# open a shell and go to the evil-surround directory, after cloning it
# this is a clean emacs with just the absolute minimum dependencies needed to test evil-surround interactivelly.
make
make emacs
# now load evil-surround/test/evil-surround-test.el and M-x ert and run the tests
#+END_SRC
** command
#+BEGIN_SRC sh
# open a shell and go to the evil-surround directory, after cloning it
# this commands ensure that the tests are using a clean emacs with just the absolute minimum dependencies needed.
make
make test
#+END_SRC
* Credits
Credits and many [[https://github.com/emacs-evil/evil/issues/842][thanks]] go to [[http://github.com/timcharper][Tim Harper]], the original mantainer of the package.
* LICENSE
- [[https://www.gnu.org/licenses/gpl-3.0.en.html][GNU General Public License v3]]
#+BEGIN_SRC text
GNU General Public License v3
Copyright (C) 2010 - 2017 Tim Harper
Copyright (c) 2018 - 2020 The evil-surround Contributors
#+END_SRC
|