30

Let's say that I have a code like this (| represents the cursor position):

func1(x|, func2(), y); 

I would like to get:

func1(x|);

Is there a way to delete the code from the position of the cursor to the position preceding the right end of the current inner block?

I know that I can go with dt). but I wonder if there is a way to mix it with what di) does.

2
  • 1
    I'm interested in knowing if there's an easy way to "delete the left/right half of inner/outter block", as you asked. But as a side note, I would probably do C); in this particular case.
    – Shahbaz
    Nov 29, 2016 at 4:06
  • 1
    Sometimes the % motion can do what you're looking for (i.e. d%).
    – alxndr
    Nov 29, 2016 at 5:20

5 Answers 5

44

I would use

d])

which means delete (d) to the next unmatched ')' (])).

See :help ]).

1
  • How would you do this if you were inside a string. For example when I try function( bob, "a | string", otherParams) hitting d]) with the cursor at | does nothing (sends a bell code)
    – Cole
    Mar 13, 2021 at 0:32
5

Motions go only in one direction while text-objects go only in two directions.

This means that you can't have half of a text-object unless you create a custom operator pending motion that uses that text-object under the hood or mimics its behavior.

In your example, the text covered by i) is pretty easy to visualize:

func1(x, func2(), y);
      ^^^^^^^^^^^^^

but how would you tell Vim to operate from the cursor to the end of that text? One would need to create custom operators like obi) and oei) (semi-random examples).

" ()
onoremap oei) :normal! vi)o``<CR>
onoremap obi) :normal! vi)``<CR>

" []
onoremap oei] :normal! vi]o``<CR>
onoremap obi] :normal! vi]``<CR>

" {}
onoremap oei} :normal! vi}o``<CR>
onoremap obi} :normal! vi}``<CR>

" ""
onoremap oei" :normal! vi"o``<CR>
onoremap obi" :normal! vi"``<CR>

" ''
onoremap oei" :normal! vi'o``<CR>
onoremap obi" :normal! vi'``<CR>
1
  • 4
    Would be interesting to create a generic motion that re-uses all already defined text-objects, combined with the current cursor position; for example, instead of ib, imb to the right and iMb to the left, and so on (automatically).
    – VanLaser
    Nov 29, 2016 at 16:16
4

For this specific case I would dfy

For the general case:

  • dT( delete from the cursor to the start of the block
  • vib select the rest of the inner block
  • p replace the inner block with what you just deleted

You could make it into a mapping.

 :map K dt(vibp
3

The other existing answers are all dependent on vim's definition and detection of a block. My strategy for this kind of deletions is to use the c command combined with with the f motion and the actual character to stop at. This will then actually delete the stop character, but since it also was the last key you pressed repeating it twice has next to zero cost, and that will insert it again since c changes to insert mode.


To explain with examples, for

func1(x|, func2(), y); 

the command c2f)) will give

func1(x)|;

which might at first seem less elegant than some of the other answers, however notice that this strategy is universal and does not depend on any block definition.


For instance with

<div| class="some-class">text</div>

the command cf>> will give

<div>|text</div>

Or when editing csv files like

2016-11-29,question,vi|.stackexchange.com,10435

the command cf,, will give

2016-11-29,question,vi,|10435

Often I use this to delete the rest of a string, from

printf("Hello world| - a boring example\n");

to

printf("Hello world\|n");

with cf\\

or from

print("Hello world| - a boring example");

to

print("Hello world"|);

with cf"".


This does change the current position to a slightly different place than asked for, and also changes into insert mode. But I wanted to share my go-to-solution for deleting the rest of anything.

2
  • 1
    The problem with cf solution is that I have to specify the character where I want to stop deleting. The questions asks what to do if you cannot simply do cf) because there's another ) before the ) you actually want to reach (for example when you want to change func(x|, g(x, x), x, x, g(x, x)) to func(x)). Basically, I wanted to know if I can avoid pressing . after cf). Nov 29, 2016 at 21:54
  • Note that you can also use t instead of f to delete up to but not including the given character, so for your first example (func1(x|, func2(), y);), you could just use d2t). As @MateuszPiotrowski mentions though, it's not a general solution and requires you to know which character you want to delete to. As you generally know which character ends the block you're in for a given language though, that's not so bad.
    – Haegin
    Dec 7, 2016 at 12:30
3

The vim-ninja-feet plugin might be what you're looking for. From what I understand, it makes d[ and d] into "delete from cursor to start/end of text object", so d]i) should be "delete until end of surrounding parentheses".

Your Answer

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

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