Surround
ds, cs, ys โ operate on surroundings as a first-class concept.
Tim Pope's vim-surround adds three operators โ ys (add), ds (delete), cs (change) โ plus visual mode S. The trailing key names the surrounding kind: quotes, brackets, tags, or function calls. Once you have it, it feels like core Vim.
Vim's text-object grammar already lets you talk about the content inside surroundings โ i", i(, it all select what's between the delimiters. But the delimiters themselves โ the quotes, the brackets, the tags โ are second-class: you can land your cursor on one with a motion, but you can't directly operate on "the thing wrapped around this word." Tim Pope's [vim-surround](https://github.com/tpope/vim-surround) plugin closes that gap. It adds three operators that treat surroundings as first-class targets, completing the grammar. It's the plugin most often cited as "this should ship with Vim."
The Grammar
Every surround command is one sentence with two slots: operator + kind The operator says what to do. The kind is a single key naming the surrounding โ ', ", (, [, {, <, t (tag), f (function call). The cs operator takes two kinds because changing requires both an old and a new wrapper.
| Form | Operator | Reads as |
|---|---|---|
| dskind | Delete | delete-surrounding-kind |
| cs*old**new* | Change | change-surrounding-old-to-new |
| ys*motion**kind* | Add | you-surround the range with kind |
| ysskind | Add (whole line) | Surround the current line |
| Visual mode + Skind | Add (selection) | With a selection already made in visual mode, press S then kind to wrap the selection. |
ys is the only operator that takes a motion (or text object) before the kind โ the motion picks what gets wrapped. ds and cs need no motion: they search outward from the cursor and operate on the nearest enclosing surround.
Kinds โ the Surround Alphabet
The kind key names a category of wrapper. Quotes are their own pair. Bracket pairs have two flavors: the opener form ((, [, {, <) adds a space on the inside; the closer form (), ], }, >) does not. Tags and function calls prompt for the missing piece (tag name, function name).
| Kind | Wrapper | Notes |
|---|---|---|
| ' " ` | Quotes | Self-pairing โ same character on both sides. |
| ( or ) (alias b) | Parens | ( adds spaces inside: ( foo ). ) does not: (foo). |
| [ or ] | Square brackets | [ adds spaces, ] does not. |
| } or { (alias B) | Curly braces | Opener form adds spaces; closer form does not. |
| < or > | Angle brackets | Plain <โฆ> โ not a tag, just the symbols. |
| t or T | HTML/XML tag | Prompts: type em> (or a href="...">) and press Enter. Closing tag generated. T keeps the full opening tag on change. |
| f | Function call | Prompts for a name; produces name(content). |
| F | Function call (spaced) | Like f but name( content ). |
Worked Examples
| Sequence | Before โ After |
|---|---|
| ds' | 'hello' โ hello |
| dst | <em>hello</em> โ hello |
| cs'" | 'hello' โ "hello" |
| cs[( | [hello] โ ( hello ) |
| cs]) | [hello] โ (hello) |
| cst | <em>hi</em> โ prompts for new tag โ <strong>hi</strong> |
| ysiw' | hello โ 'hello' (inner word) |
| ysiwf | hello โ print(hello) (prompts for print) |
| yss} | foo = 1 โ {foo = 1} (whole line, no spaces) |
| yss{ | foo = 1 โ { foo = 1 } (whole line, with spaces) |
| ysip<p> | wraps paragraph in <p>โฆ</p> |
| Visual mode + S' | wraps the selection in single quotes |
Doubled and Capital Forms
Some shortcuts and variants follow the same operator-doubling pattern as core Vim (dd, yy):
| Sequence | Effect |
|---|---|
| ysskind | Surround the whole current line (no motion needed). |
| yS*motion**kind* | Like ys but place content on its own indented lines. |
| ySSkind | Whole-line version of the above. |
| Visual mode + gSkind | From an existing visual mode selection, gS wraps it like S but puts the content on its own lines. |
See also: Quote Text Objects, Bracket Text Objects, HTML/XML Tag Objects, The Vim Grammar