13

Let's say I have a line like this:

a = x(y(z));

And I want to change it to:

a = y(z);

What's the most efficient way to do this?

1
  • With my vim-surround-funk plugin, you would do dsf (with the cursor on the x( or the associated ). This plugin also allows you to delete, change and yank a surrounding function call, and paste it around any text object (and there's a text object for function calls, so you can paste it around them too!)
    – mattb
    Feb 1, 2022 at 13:28

3 Answers 3

3

If you start with your cursor on the x type

%x``2x

  • % move to the corresponding parenthesis to the one closest to you, i.e. )
  • x delete it
  • `` jump back to your previous jump, the starting x
  • 2x delete the next two characters, x(

If you want this to be more robust you can do a find next and delete instead of the 2x

%x``df(

This works when your function name is variable length.

3
  • Thanks! Alternatively dwx instead of df) Apr 17, 2015 at 20:51
  • Huh.. I didn't know I could do ``!
    – Roflo
    Apr 17, 2015 at 22:06
  • It is the "last source of a jump" location.
    – jecxjo
    Apr 17, 2015 at 22:41
9

What I use a mapping that leverages Tim Pope's surround.vim:

nmap <silent> dsf ds)db

I use the mapping dsf to read as delete surrounding function. Execute this mapping while inside the function call or one of the parens. The mapping is supposed to be the opposite of surround.vim's surround with function mappings, e.g. Sf.

1
  • 1
    There is also a PR to add dsf to surround.vim itself.
    – Hotschke
    May 2, 2015 at 7:57
0

Exchange

Using exchange.vim, when one of the defined regions to exchange is fully inside the other, the smaller one replaces the larger one.

So, with your cursor on the beginning of the function name, you can use cx%%cxi(.

Explanation

  • The cx operator is used in pairs: the first time defines the first region to be exchanged, and the second time defines the second region and performs the exchange. It takes any motion or text object, given after the operator.
  • cx% defines the first region to exchange as the text from the current cursor position (beginning of function name) to where the % motion goes. When not on a bracket, % scans forward in the current line until it finds one, then jumps to the matching bracket. After this command, the entire function call will be highlighted.
  • % moves the cursor to the closing parenthesis of the function call.
  • cxi( defines the second region to exchange as the inner parenthesized term (so, the function arguments). At this point, the exchange is performed.

Caveat

If there is any %-matchable character before the opening parenthesis for the function call, this pattern falls apart. For example, the following example code would be valid in JavaScript:

foo[x](arg);

However, the first region would be defined as foo[x] and the second one would fail (no matching parenthesized term).

7
  • Didn't quite work. My configuration (and maybe its different than yours) of exchange.vim doesn't move the cursor to the ) after the first sequence but rather leaves it at the beginning. I had to move two words (the 'x' and '(' ) and then apply. So basically cx%2w.
    – jecxjo
    Apr 22, 2015 at 19:03
  • Oops. To tell the truth, I didn't try this before posting. A more reliable way would be to type % again. I'll update the answer.
    – tommcdo
    Apr 22, 2015 at 19:05
  • Using the . method should use % as exchange.vim is setup to use the same cut mechanism when triggered this way.
    – jecxjo
    Apr 22, 2015 at 19:07
  • Ooh, that's clever! Updating the answer again haha
    – tommcdo
    Apr 22, 2015 at 19:09
  • Wait, that leaves the parentheses intact. Not what the OP asked for.
    – tommcdo
    Apr 22, 2015 at 19:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.