29

I am new to vim and in the process of discovering tons of interesting things that one can using this powerful editor.

One particular thing that I need to do very frequently is to change a pair of parenthesis in the text to square-brackets (for example to change ( (a+b+c) ) to [ (a+b+c) ]) or vice-verso. I now do this by manually changing the two characters ( and ) to [ and ].

However, when there is a lot of text in between the parenthesis, it could be difficult to locate the pair of opening and closing parenthesis especially because after changing the first ( to [ then the % command will no longer be able to find the corresponding ).

I was wondering if there is a better and quicker way to make such changes?

Randall
  • 2,859
  • 1
  • 21
  • 24
MikeL
  • 2,369
  • 2
  • 24
  • 38

6 Answers6

48

I personally use https://github.com/tpope/vim-surround as it provides everything I could ever need, reading through the source you can see the solution is non-trivial.

A typical example:

Hello("World")

with the cursor somewhere between the (), you can type cs([ in normal mode to get:

Hello["World"]

surround.vim is easily installed with either Pathogen or Vundle, personally I prefer vundle. https://github.com/VundleVim/Vundle.vim

adding the important commented point:

cs([ adds spaces in the block, this should be cs)]
Snehal Parmar
  • 5,453
  • 3
  • 35
  • 46
Lee Hambley
  • 6,270
  • 5
  • 49
  • 81
23

I would simply do it like this: %r]^or[.

Here's an explanation:

  • f( -- put cursor on first parenthesis you want to change (if it's not already there).
  • % -- jump to the matching parenthesis.
  • r] -- replace the parenthesis with a bracket.
  • CTRL-O -- jump back to to first parenthesis.
  • r[ -- replace the parenthesis with a bracket.
Ben
  • 1,113
  • 1
  • 7
  • 14
6

surround.vim https://github.com/tpope/vim-surround

with this plugin, you can (cursor on or in (), cs([ to achieve your goal.

Kent
  • 189,393
  • 32
  • 233
  • 301
6

With lh-brackets, I would use <m-b>( to change any pair of bracket-like characters (cursor on the first/last character of the pair) to a pair of parenthesis. <m-b>{ -> curly-brackets, and so on.

For the curious ones, this is how it works -- see s:ChangeTo(). Internally, I do a %r]``r[, and I have a dedicated treatment for quote characters.

Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83
  • 1
    Upvoting this because I really like the ```%r]``r[``` you mention in a comment to another answer on this page that you're using it deep inside your mappings. It's using only built-in vim features, and has stuck with me. – Randall Jul 21 '16 at 20:36
  • Thanks @Randall. Actually, I've rewritten it lately to support quote characters as well. The function is a little bit more complex now. BTW I've updated to link to the "new" github repo. – Luc Hermitte Jul 22 '16 at 08:04
1

Without any plugin it can be done by deleting the content inside the parenthesis and yanking in the new bracket (from anywhere within the bracket):

di(a[]<esc>P%2X

Obviously more key that using surround but but not that many ;-)

Note

There is no need to remember the sequence of key but only to start by deleting the inside of the brackets. Then it's just normal vim fu.

mb14
  • 22,276
  • 7
  • 60
  • 102
  • 1
    That does not look right. It seems to not delete the initial surrounding parens correctly. This is what I came up with: `yi)ca)[0]` – Peter Rincker Aug 20 '14 at 13:17
  • @Peter, you can change `ca)` to `c%`. – Luc Hermitte Aug 20 '14 at 13:24
  • @peter: I delete the inside of the parentheses, insert some new brackets, insert the deleted content between them, THEN delete the initial surrounding parentheses `2x` – mb14 Aug 20 '14 at 13:44
  • @mb14 I understand what you are going for. The `2x` to delete the parens will not work where your cursor is after the `%` motion, on the `[`. Instead it will delete a `[` and one more character to the the left. To see this setup the test case, `( (a+b+c) )`. Put your cursor on one of the outer parens and run `:exe "norm! di(a[]\P%2x"`. This will execute your vim snippet without any mappings you can see what I see. – Peter Rincker Aug 20 '14 at 13:59
  • Sorry, I meant `2X` not `2x'. Also, it's not really a snippet but something you can do on the fly. – mb14 Aug 20 '14 at 14:08
  • One character to the right not left. Silly me getting mixed up this morning. @LucHermitte you are correct. Nice vim golf – Peter Rincker Aug 20 '14 at 14:08
  • 3
    I'm actually doing `%r]``r[` deep inside my mappings which is even shorter, and which works only when the cursor is on the first character. – Luc Hermitte Aug 20 '14 at 14:18
  • @mb14 Absolutely! Do not memorize it. It should be noted that breaking this up into multiple steps and not using something like surround will mean the following: 1) More undo history 2) Cannot repeat with `.` (Assuming repeat.vim) 3) Will not properly set `[` and `]` marks. That isn't even mentioning the fact that surround.vim does tags! But it is nice to know that even on a remote system you can handle this scenario without too much trouble. – Peter Rincker Aug 20 '14 at 14:32
  • How about this variation on @mb14: `di(a[]P`? Yes, the @mb14 usage of capital `X` to delete is more cool (and is now another tool in my bag), and yes it somehow feels *dirty* to be using a `` in Vim, but I thought I would put it out there and leave others to make up their own mind. – Robert Nov 07 '14 at 07:35
0

Based on a few of the SO's around this matter (see my comment in the @mb14 answer here), I was thinking of muscle-memorizing something like this:

di(a<bkspace><bkspace>[]<Esc>P

but what I really wanted to do was this:

di(c%[]<Esc>P

You will see that you cannot do that because the c puts the () brackets into your 0 register and therefore you actually need to do this:

di("_c%[]<Esc>P

or (I was also trying out a 'yank' approach and came up with) this:

yi(ca([]<Esc>"0P

Okay, neither is too bad, but it occurred to me that this is going to all go much better if I map <leader>c to "_c so that I have a real delete and can do this:

di(\c%[]<Esc>P

or this:

yi(\ca([]<Esc>P

Both are pretty close to what I wanted to do, and the thought process has given me one of the most valuable lines in my $MYVIMRC:

noremap <leader>c "_c
Community
  • 1
  • 1
Robert
  • 1,530
  • 1
  • 16
  • 24