Here is why the question should have been on SO : non trivial scripting is required...
" Public Mappings {{{1
onoremap <silent> i% :<c-u>call <sid>SelectFirstPair(1,0)<cr>
xnoremap <silent> i% :<c-u>call <sid>SelectFirstPair(1,1)<cr><esc>gv
onoremap <silent> a% :<c-u>call <sid>SelectFirstPair(0,0)<cr>
xnoremap <silent> a% :<c-u>call <sid>SelectFirstPair(0,1)<cr><esc>gv
" Public Mappings }}}1
"------------------------------------------------------------------------
" Private Functions {{{1
" Note: most functions are best placed into
" autoload/«your-initials»/«omap_any_bracket».vim
" Keep here only the functions are are required when the plugin is loaded,
" like functions that help building a vim-menu for this plugin.
let s:k_pairs = {
\ '(': ')',
\ '[': ']',
\ '{': '}',
\ '<': '>'
\ }
let s:k_begin = '[([{<]'
let s:k_end = '[)\]}>]'
function! s:SelectFirstPair(inner, visual)
" In case we already are in visual mode, we may have to extend the current
" zone if it selects a pair of brackets
if a:visual
let char_b = lh#position#char_at_mark("'<")
if char_b =~ s:k_begin
\ && s:k_pairs[char_b] == lh#position#char_at_mark("'>")
call search('.', 'bW') " previous char
elseif a:inner
" handle case the case "vi%i%i%"
let current_pos = getpos('.')
call setpos('.', getpos("'<"))
call search('.', 'bW') " previous char
let pos_b = getpos('.')
call setpos('.', getpos("'>"))
call search('.', 'W') " next char
let pos_e = getpos('.')
let char_b = lh#position#char_at_pos(pos_b)
let char_e = lh#position#char_at_pos(pos_e)
echomsg "chars = ".char_b.char_e
if char_b =~ s:k_begin
\ && s:k_pairs[char_b] == char_e
call setpos('.', pos_b) " restore start_pos
call search('.', 'bW') " previous char
else
call setpos('.', current_pos) " restore init_pos
endif
endif
endif
" Searching the n outer blocks requested
let cnt = v:count <= 0 ? 1 : v:count
while cnt > 0
let cnt -= 1
let char_c = lh#position#char_at_pos(getpos('.'))
let accept_at_current = char_c =~ s:k_begin ? 'c' : ''
" Begin of the current outer block
if 0 ==searchpair(s:k_begin, '', s:k_end, 'bW'.accept_at_current, 'lh#syntax#skip()')
throw "No outer bloc"
endif
if cnt > 0
call search('.', 'bW') " previous char
endif
endwhile
let char_b = lh#position#char_at_pos(getpos('.'))
normal! v
" End of the outer block
let pos_e = searchpair(s:k_begin, '', s:k_end, 'W', 'lh#syntax#skip()')
let char_e = lh#position#char_at_pos(getpos('.'))
if pos_e == 0
throw "pos_e == 0"
elseif s:k_pairs[char_b] != char_e
echomsg "unbalanced blocks"
endif
" Adjusting the extremities
if a:inner
call search('.', 'b')
normal! o
call search('.')
normal! o
endif
endfunction
" Private Functions }}}1
NB: I've reused function from lh-vim-lib -- BTW, there is a little bug in the version of lh#position#char_at_pos()
in conf: col()
must not be used.
line 13: E15: Invalid expression: E15: Invalid expression: {
(…). I have vim 7.2, does your code require 7.3? By the way, while programming questions are usually redirected to SO, scripting answers (for shells, editors and other scriptable programs) are common here.