evil-surround and the port of surround.vim to the Evil vi layer
you will be surrounded (surround.vim for evil, the extensible vi layer)
At a glance
- What is it?
- evil-surround is a single Emacs Lisp file that emulates Tim Pope's surround.vim on top of the Evil vi layer. It gives you y, c and d surround operations with text objects, and it is configurable down to a buffer-local alist of surround pairs.
- Who is it for?
- evil-surround fits Emacs users who already use Evil and want surround.vim style text object editing without leaving their init file. It does not fit someone who wants a general purpose structural editing package, because the package only covers surrounding and requires Evil for its vi layer.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 138 days ago.
- What is it written in?
- Mainly Emacs Lisp, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A single file that emulates one Vim plugin
The package states its purpose in one line: it emulates surround.vim by Tim Pope, and the functionality is wrapped into a minor mode. There is no other claim to make about it. This is not a general structural editing toolkit with a surround feature bolted on, it is a port of one specific Vim plugin to one specific Emacs vi layer.
The dependency is explicit as well. The package uses Evil as its vi layer, which means the key bindings discussed below assume you are already running Evil's normal, visual and operator states. Installing evil-surround without Evil gives you a minor mode whose commands are bound in maps that Evil defines, so the sensible order is Evil first, surround second.
The repository is small in the way a well-scoped port should be. The top level contains evil-surround.el, a Makefile, a readme.org, a license.md file and a test directory. The whole implementation lives in that one Lisp file, which is a reasonable thing to read if you want to know exactly what a surround operation does before trusting it with your buffer.
Surrounding, changing and deleting are three separate key sequences
The command surface follows surround.vim closely, and it is split across visual state and normal state.
To add a surrounding you use S followed by a text object in visual state, or gS followed by a text object. In normal state the equivalents are ys and yS followed by a text object. Changing an existing surrounding uses cs with the old text object and then the new one. Deleting uses ds with a text object.
The reason there are two forms in each state is the usual one in Vim: the uppercase variants include the surrounding characters in the operation, so they replace the whole delimited region rather than only what is between the delimiters. The README does not spell that out in prose, which is a small gap, but the naming pattern is consistent enough that a Vim user will recognise it immediately.
The important thing for a new user is that a text object is the operand. ds, then iw, deletes the surrounding around the inner word. cs, then iw, then a character, changes it. The set of text objects is Evil's, not the package's, so anything Evil can select you can surround.
Surround pairs are a buffer-local alist of trigger characters
The configuration variable is evil-surround-pairs-alist, and the documentation suggests inspecting it with C-h v evil-surround-pairs-alist. Each entry pairs a trigger character with a left and a right string, for example:
(?> . ("<" . ">"))An entry can also be a trigger character and a function to call, in which case the function supplies the pair:
(?< . surround-read-tag)The reason the alist is buffer local is the useful part of the design. It means different modes can have different pairs, and a mode hook is enough to arrange that. The documentation warns that the less-than trigger defaults to inserting a tag, which is not what you want in C++ where angle brackets are the useful surround, so it gives a hook that pushes an angle bracket pair onto the list:
(add-hook 'c++-mode-hook (lambda ()
(push '(?< . ("< " . " >")) evil-surround-pairs-alist)))The same trick applies to backtick in Emacs Lisp modes, where the default entry is unhelpful:
(add-hook 'emacs-lisp-mode-hook (lambda ()
(push '(?` . ("`" . "'")) evil-surround-pairs-alist)))The documentation notes that having two entries for the same trigger is not an error, since surround takes the first one it finds. To change the defaults globally you need setq-default, either clearing the list:
(setq-default evil-surround-pairs-alist '())or pushing a pair onto it, for example to surround with two backticks when you type a tilde:
(setq-default evil-surround-pairs-alist
(push '(?~ . ("``" . "``")) evil-surround-pairs-alist))Text objects can be defined for surround to use
Adding a surround pair is one thing, but sometimes you want to surround with delimiters that have no trigger character of their own, or you want a text object that Evil does not already provide. The package handles the second case by respecting text objects you define yourself.
The documented approach defines an Evil text object and binds it, using a macro that the documentation attributes to a Stack Overflow answer. The macro creates an inner and an outer variant of the same object and binds both to the relevant text object maps:
(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))))With the macro in place, defining objects is a one-liner each, and the package's own examples cover the common quoted delimiters:
(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 regexThe dollar example carries an inline comment about escaping the regex, which is a hint that these objects are defined by regular expressions and that a literal character may need a backslash.
There is also a documented path for buffer-local text objects, so that a mode specific object does not pollute the global keymap. The example binds pipes to Q in a local inner and outer keymap and then registers those keymaps in evil-surround-local-inner-text-object-map-list and evil-surround-local-outer-text-object-map-list, alongside a setq-local that appends a Q pair to the buffer's own evil-surround-pairs-alist.
Enabling the mode and extending the operator list
Installation is either through use-package or by hand. The README gives the use-package form, to be added to ~/.emacs or ~/.emacs.d/init.el:
(use-package evil-surround
:ensure t
:config
(global-evil-surround-mode 1))The alternative is to add the evil-surround.el file to your load-path and put (require 'evil-surround) in your init file. If you would rather not enable it everywhere, the documentation says you can enable surround-mode for a given major mode by adding turn-on-surround-mode to the mode hook.
The other extension point is the operator list. New operators are added through evil-surround-operator-alist, with the same C-h v convention for inspecting it. By default surround works with evil-change and evil-delete, which matches the cs and ds commands. The README is cut off at the point where it explains how to add support for further operators, so the details of which operators are safe to enable are not in the text available here.
A project that needs a different operator, for example to keep the surrounding but change only the text inside it, is where you would need that section of the documentation. Reading the source of evil-surround.el is the fallback, and for a file this size that is a reasonable amount of reading.
The Makefile clones Evil and drives a batch test run
The development side of the package is a Makefile with a handful of targets, and the variables at the top set out how it works:
emacs ?= emacs
bemacs = $(emacs) -batch -l test/elpa.el
LIBS = -L evil -L evil/libThe update target regenerates a file under test and clones Evil itself with a shallow clone if the evil directory is not present, so the package is always tested against the current Evil rather than a pinned copy. The emacs target launches a batch Emacs with no user configuration, loads Evil and its goto-chg library from the cloned checkout, loads evil-surround.el, and then enables both Evil and the surround mode. That is a good template for reproducing the package's own environment.
The test and compile targets both run through the bemacs batch wrapper, loading test/make-test.el and test/make-compile.el respectively, with compile depending on a clean step. The clean target removes the compiled .elc files, and the .PHONY line lists update, compile, test and clean.
The test directory in the repository is the only place the test scripts live, and the file list shows the package uses a .travis.yml for continuous integration, which is a dated choice but still runs.
Where evil-surround is the wrong tool
The first wrong case is obvious from the dependency. If you do not use Evil, there is no point in installing this, because the keys only make sense inside Evil's normal, visual and operator states. There are other ways to get structured editing in Emacs, and this package is not one of them.
The second is the scope. The package covers surrounding and nothing else. If what you want is a full structural editing layer with select, swap, extract and raise operations over nested structures, a different package exists for that job, and the difference is not in the details but in the shape of the tool: a surround port has three commands and a pair table, while a structural editing package gives you a family of operators that work on a parse tree of delimiters. Neither is better; they answer different questions.
The third is a gap in the documentation. The readme.org is organised as a set of org source blocks, and it ends mid-sentence in the section about adding new supported operators. The list of operators beyond evil-change and evil-delete is therefore not something you can read here, and if your workflow needs a surround operator that is not change or delete you will have to look at evil-surround.el or the rest of the documentation.
On licensing, the repository records a custom licence that GitHub cannot classify, in a file called license.md, while the readme.org badge points at the GNU GPL version 3 text. The two are not the same thing and the metadata does not resolve the difference, so read license.md before you copy any of this code into a project with different terms. The repository is not archived and the last push was on 2026-06-07, with no GitHub releases tagged, so versions are tracked by commits in the master branch rather than by release tags.
Editorial conclusion
evil-surround fits Emacs users who already use Evil and want surround.vim style text object editing without leaving their init file. It does not fit someone who wants a general purpose structural editing package, because the package only covers surrounding and requires Evil for its vi layer. Before adopting it, check that Evil is already your vi layer, and look at evil-surround-pairs-alist in your init file, because the default behaviour of the less-than trigger differs between C++ and Markdown modes.
Frequently asked questions
How do I install and enable evil-surround in Emacs?
With use-package, add (use-package evil-surround :ensure t :config (global-evil-surround-mode 1)) to your init file, or put evil-surround.el on your load-path and (require 'evil-surround) in the init file. Evil itself has to be present, since evil-surround uses it as its vi layer.
What key bindings does evil-surround provide?
Surround an area with S or gS in visual state, or ys and yS in normal state, followed by a text object. Change a surrounding with cs and an old and a new text object, and delete one with ds and a text object.
How do I add my own surround pairs to evil-surround?
Add entries to evil-surround-pairs-alist, where each entry is a trigger character with a left and a right string such as (?> . ("<" . ">")). The alist is buffer local, so a mode hook can push a different pair for a given major mode.
What licence does evil-surround use?
The repository is recorded as using a custom licence that GitHub cannot classify, held in the license.md file, while the readme badge points at the GNU GPL version 3 licence text. The terms of the license.md file are the ones to check before reuse.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/emacs-evil-evil-surround)Was this useful?