38

Is there a functionality in Vim that allows parenthesis to be added around the highlighted text?

For instance, if I highlight n = getchar() in if (n = getchar() == '\n'), I would want to put parenthesis around that.

6 Answers 6

41

You need an awesome and must-have plugin surround. Then, it will happily do what you want if you select text and type Sb (surround-braces), or S) (note the capital S !).

It actually can do a lot of surrounding: various quotes, tags, etc. It allows you to put cursor in the double-quoted word and change double quotes to single quotes by typing: cs"' (change-surround " to '). Or you can completely delete quotes by typing ds" (delete-surround ").

Read the docs by link, it is really awesome!

6
  • 2
    You didn't explain how to do it with the selection, though. I got led here because it wasn't immediately obvious. Aug 5, 2016 at 13:24
  • @JackHasaKeyboard, what do you mean I didn't explain how to do it with the selection? The second sentense in my answer says: > Then, it will happily do what you want if you select text and type sb (surround-braces), or s). Aug 5, 2016 at 14:31
  • 2
    So you did. Not working for me though, hitting s just deletes the selection and enters insert mode. Aug 5, 2016 at 14:43
  • 1
    It means that the "surround" plugin I mentioned in my answer is not correctly installed. Aug 5, 2016 at 14:51
  • Awsome indeed. I've been using it for a while and can bet. Mar 14, 2017 at 10:42
37

In addtition to Dmitry's suggestion of the surround plugin, adding parenthesis around highlighted text can be done with the following command:

xi()<Esc>P

You can set a map in visual mode using (for example) \s by adding the following to your ~/.vimrc file:

xnoremap <leader>s xi()<Esc>P
5
  • 2
    This looks like a nice and simple solution. If I don't find any issues with this in the future, I'll prefer this over additional plugins. Thanks! Nov 13, 2016 at 18:05
  • 3
    It's a good solution, but not quite as complete as using the surround plugin as it doesn't work if you are selecting whole lines (using V instead of v). In this case it just pastes the lines below your parens. Oct 9, 2017 at 18:04
  • 1
    I had to use di()<Esc>P as x doesn't yank the selected word into a paste buffer for me. You can also use vnoremap for the shortcut to work in both visual and select modes, rather than just visual.
    – Aaron D
    Aug 20, 2020 at 17:56
  • You can also record a macro as well.
    – lkahtz
    Dec 25, 2020 at 5:56
  • Another variation: c()<Esc>P.
    – itachi
    Mar 8, 2022 at 10:08
24

The command

c()<Esc>P

Explanation

If you want to put the word under the cursor in to brackets this is viwc()<Esc>P.

viw will visually select all charactrs in a word.

c() will cchange the selection and drops you into insert mode, where you type the literal characters ( ). Also, c automatically copies the original content to your yank buffer (clip board).

With <Esc>P you return Escback from insert to normal mode and Paste the previous content.

1
  • 2
    I think you want (capital) P so that the word is pasted between the parentheses instead of after them. Sep 24, 2020 at 23:39
3

Building on dotancohens answer, I put the following in my .vimrc:

xnoremap <leader>( <ESC>`>a)<ESC>`<i(<ESC>

You can easily make similar mappings for [], {}, etc. It works by jumping to the start and end markers implicitly set after ending visual mode. This way selecting whole lines will add the parens at the start/end of the first/last line; it won't overwrite your yank register; and it'll leave the cursor right before the opening paren.

1

lh-brackets simply binds ( to surround the selection with the brackets. Unlike surround it doesn't follow the vim usual keybinding philosophy as does. Instead less keys are required.

Otherwise, there are many ways to proceed. If you don't mind messing the unnamed register, you also use s(^R")<esc> (^R like CTRL-R)

0

My answer is a bit more complex but it might be useful to someone. I go the extra mile so that none of my registers get used by macros or functions.

function! WrapWith(startChar, endChar) range
    let l:beg = getpos("'<")
    let l:end = getpos("'>")
    execute "normal! `>a".a:endChar
    execute "normal! `<i".a:startChar
endfunction

"REMAPS

"Wrappers
vnoremap <silent> (( :call WrapWith("(", ")")<CR>
vnoremap <silent> [[ :call WrapWith("[", "]")<CR>
vnoremap <silent> {{ :call WrapWith("{", "}")<CR>
vnoremap <silent> << :call WrapWith("<", ">")<CR>

Some bonuses for ya:

augroup Clang
  autocmd!
  autocmd FileType c,java,javascript setlocal formatoptions+=croq comments=sO:*\ -,mO:*\ ,exO:/{,exO:*/}
  autocmd FileType c,java,javascript,javascriptreact,scss inoremap <buffer> ** /**/<Left><Left>
  autocmd FileType c,java,javascript,javascriptreact,scss vnoremap <buffer> <TAB>/ :call WrapWith("/*","*/")<CR>
augroup END

No need for a plugin IMO.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .