How to quickly select parenthesized text from outside of the parentheses in Vim?
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