Emacs Redux: surround.el: Vim-Style Pair Editing Comes to Emacs

Wait 5 sec.

In my recent article on removing paired delimiters, I mentioned that I kind ofmiss Vim’s surround.vim experience inEmacs. Well, it turns out someone has done something about it –surround.el brings the core ideas ofsurround.vim to native Emacs, without requiring Evil mode.surround.vim (and similar plugins likemini.surround in Neovim) aresome of my favorite Vim packages. The idea is so simple and so useful that itfeels like it should be a built-in. So I’m happy to see someone took the time toport that beautiful idea to Emacs.The Core Ideas of surround.vimFor those who haven’t used surround.vim, the concept is straightforward. Youhave a small set of operations for working with surrounding characters –the delimiters that wrap some piece of text: Delete surrounding pair: ds( removes the parentheses around point Change surrounding pair: cs(" changes parens to quotes Add surrounding pair: ys + motion + character wraps text with a delimiterThat’s basically it. Three operations, consistent keybindings, works everywhereregardless of file type. The beauty is in the uniformity – you don’t needdifferent commands for different delimiters, and you don’t need to think aboutwhich mode you’re in.surround.el in Practicesurround.el is available on MELPA and the setup is minimal:(use-package surround :ensure t :bind-keymap ("M-'" . surround-keymap))You bind a single keystroke (M-' in this example) to surround-keymap, and thatgives you access to all the operations through a second keystroke. Here are thecommands available in the keymap: Key Operation s Surround region/symbol at point d Delete surrounding pair c Change pair to another k Kill text inside pair K Kill text including pair i Mark (select) inside pair o Mark including pair There are also shortcuts for individual characters – pressing an openingdelimiter (like () after the prefix does a mark-inner, while pressing theclosing delimiter (like )) does a mark-outer.A Short WalkthroughLet’s see how this works in practice. Starting with the word Hello (with pointsomewhere on it):Surround – M-' s " wraps the symbol at point with quotes:Hello → "Hello"Change – M-' c " ( changes the surrounding quotes to parens:"Hello" → (Hello)Mark inner – M-' i ( selects just the text inside the parens:(|Hello|) ;; "Hello" is selectedMark outer – M-' o ( (or M-' )) selects the parens too:|( Hello)| ;; "(Hello)" is selectedDelete – M-' d ( removes the surrounding parens:(Hello) → HelloKill – M-' k ( kills the text inside the pair (leaving the delimitersgone too), while M-' K ( kills everything including the delimiters.Inner vs. OuterLike surround.vim, surround.el distinguishes between “inner” (just thecontent between delimiters) and “outer” (content plus the delimiters themselves).The i and k commands operate on inner text, o and K on outer.There’s also an “auto” mode – the default for i and k – that behaves asinner when you type an opening character and outer when you type a closingcharacter. So M-' ( marks inner, M-' ) marks outer. Handy shortcut if yourfingers remember it (I’m still building the muscle memory).One caveat: auto mode can’t distinguish inner from outer for symmetric pairslike quotes (", '), since the opening and closing character are the same. Inthose cases it defaults to inner.How It Differs from VimThe biggest difference is in how you surround text. In Vim, surround.vimuses motions – ysiw( means “surround inner word with parens.” In Emacs,surround.el operates on the active region or the symbol at point. So thetypical workflow is: select something, then M-' s (.This actually pairs beautifully withexpreg (which I wrote aboutrecently). Use expregto incrementally select exactly the text you want, then M-' s to wrap it. It’sa different rhythm than Vim’s motion-based approach, but once you get used toit, it feels natural.The other operations (d, c, k, i, o) work similarly to their Vimcounterparts – you invoke the command and then specify which delimiter you’retargeting.When to Use Itsurround.el fills a specific niche: Using electric-pair-mode? Then surround.el is an excellent complement.electric-pair-mode handles auto-pairing when you type delimiters, butoffers nothing for removing, changing, or wrapping existing text withdelimiters. surround.el fills exactly that gap. Using smartparens? You probably don’t need surround.el –smartparens already has sp-unwrap-sexp, sp-rewrap-sexp, and friends. Theoverlap is significant, and adding another package on top would just beconfusing. Using paredit? Same story for Lisp code – paredit has you coveredwith paredit-splice-sexp, paredit-wrap-round, and so on. But if you wantthe surround experience in non-Lisp buffers, surround.el is a good pick. My current setup is paredit for Lisps, electric-pair-mode for everythingelse, and I’m adding surround.el to complement the latter. Early days, but itfeels right.Wrapping UpIf you’ve ever wondered whether some Vim feature you miss exists in Emacs –the answer is always yes. It’s Emacs. Of course someone has written a packagefor it. Probably several, in fact… Admittedly, I discovered surround.el onlywhen I had decided to port surround.vim to Emacs myself. :DThat’s all I have for you today. Keep hacking!