I know that I can select the text inside single or double quotes by typing vi'
or vi"
in Normal mode. For example, with the cursor located at the letter H
here:
Hello "World"
I can select the word World
by issuing vi"
.
But this does not seem to work if World
is parenthesized instead of being quoted:
Hello (World)
If my cursor is at H
and I try to select World
using vi)
, it does not work. It seems that the only way to do this is to actually move your cursor inside the parentheses first and only then issue vi)
.
Why does selecting text inside parentheses and quotes differ in this way?
The difference between {a
,i
}×{(
,)
,b
} text-object commands
and their "
, '
, `
counterparts primarily results from the
difference in definitions of a block and a quoted string
(see :help v_ab
, :help v_aquote
).
While the latter is the text from the previous quote character on the
current line until the next one on that same line (escaped ones aside),
the former is the text between the nth previous unmatched opening
parenthesis and the matching closing one. Simply put, the command
va(
(without a count) is like [(v%
—if there is no unmatched
parenthesis before the cursor, both select nothing. However,
the command va"
scans the current line to find a matching pair
of quotes, anyway.
The main reason for this difference in behavior, I suppose, is that quoted strings, in contrast to parenthesis, are assumed to be non-nested (at least in perspective of the built-in Vim text objects).
To select the text in the next parenthesis on the current line, one
can use %vi(
or %va(
, depending on whether it is desirable to
include the parentheses in the selection or not, respectively.
There is a comment on Hacker News that points to a script supposedly solving the issue.
Untested, but it’s by Steve Losh, so it might be good.
--- EDIT ---
Here is a working link and here it is copied here for posterity:
" Motion for "next/last object". For example, "din(" would go to the next "()" pair
" and delete its contents.
onoremap an :<c-u>call <SID>NextTextObject('a', 'f')<cr>
xnoremap an :<c-u>call <SID>NextTextObject('a', 'f')<cr>
onoremap in :<c-u>call <SID>NextTextObject('i', 'f')<cr>
xnoremap in :<c-u>call <SID>NextTextObject('i', 'f')<cr>
onoremap al :<c-u>call <SID>NextTextObject('a', 'F')<cr>
xnoremap al :<c-u>call <SID>NextTextObject('a', 'F')<cr>
onoremap il :<c-u>call <SID>NextTextObject('i', 'F')<cr>
xnoremap il :<c-u>call <SID>NextTextObject('i', 'F')<cr>
function! s:NextTextObject(motion, dir)
let c = nr2char(getchar())
if c ==# "b"
let c = "("
elseif c ==# "B"
let c = "{"
elseif c ==# "d"
let c = "["
endif
exe "normal! ".a:dir.c."v".a:motion.c
endfunction
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With