When using ci" the cursor does not have to reside in the double quoted area.

|String somestring = "some text";

Assuming the pipe is the cursor position, ci" will make it jump to the quoted area.

On the other hand, when using ci(, the cursor must be inside the parentheses to work and will not move the cursor inside them.

What is the reason for this difference in behavior? I assume there is a way to map the keys so that this behavior is present. Are there any drawbacks to doing this?


4 Answers 4


The main difference here is that parenthetical statements (targeted by ci() can be nested, while quoted strings (targeted by ci") cannot.

If your cursor is outside of some parenthetical statement, it could still be inside of some other one. For example (* marks the cursor position):

$foo = array(
    'x' => ar*ray(1, 2, 3),

The line the cursor is on contains (1, 2, 3), but the cursor is also inside the larger array(...) block. In this case, the larger one is the appropriate target for ci(.

If your cursor is outside of some quoted string, since they can't be nested, there's no perfectly sensible thing to do. So, Vim takes advantage and finds the first quoted string on the line.


The quote family of text objects (i', i", a', and a") are different than the rest of the text objects in that they only look at the current line. Due to this, the choice was made not to require the cursor to be within the quotes. Instead, Vim will search forward within the line to find a quoted string when the cursor isn't already inside one.

There is a discussion around some patches which would allow this forward searching behavior to be implemented for block based text objects as well.


The other answers covered why this happens. Here's a nice way to work around it.

wellle/targets.vim. I just recently found this plugin, and I think it's extremely underrated. It provides a new text object: din( Mnemonic: (d)elete (i)nside (n)ext "(". This is compatible with other operators and several different objects, such as an(, in", il( (inside last parenthesis)

It also overrides the default behavior of i( so that it first looks to see if the cursor is in parentheses, and then if it isn't it works the same way as in(. This behavior can be turned on or off. For example:

def foo(bar):
^cursor here

Typing ci( acts the same as cin(, since the cursor is not in parentheses.

def foo( ):
        ^Cursor here, and in insert mode

This also accepts a count:

def foo(bar):           #Define function foo(bar)
^cursor here

Typing c2in(:

def foo(bar):           #Define function foo( )
                                             ^cursor here

This also provides a new object, "argument". For example, dana means "Delete around the next argument". This also accepts a count. For example:

def foo(arg1, arg2, BADarg3):
^ cursor here

Typing d3ana:

def foo(arg1, arg2):
                  ^ cursor here

There are many other features this plugin has, but these are the basic ones.

  • 1
    Nice! This is a good addition. I might have to check that out.
    – Reaver
    Commented Jul 16, 2016 at 18:39
  • Great answer 10/10 but I gotta give it a 9/10 because examples are python
    – Downgoat
    Commented Jul 20, 2016 at 6:41

James mentioned a powerful plugin for this. I also made one that's much much simpler which just extends ci" to use ), }, ], <, which works with the cursor anywhere on the current line: https://github.com/Spenny1068/ciBracket

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.