If I want to, say delete a block, I can use text object motions.

I.e if my text looks like this:

(let [a 1 b {:x 3  :y 4}]

And the cursor is for example on character 3.

If I type diB then :x 3 :y 4 would be deleted If it is daB then both the block and surrounding brackets are deleted :{:x 3 :y 4}

So, the pattern is:

operation inclusion block-motion

Where operation may be:

  • d - delete

  • c - change

  • y - copy ...

inclusion is either:

  • i - inner (no brackets) or

  • a - all

and block-motion:

  • b,( or ) for () parens

  • B, { or } for {} curlies

  • [ or ] and < or > for their own respective brackets, etc..

Now, the question is: Is there a block motion for the inner-most block with brackets of any of these types?

I'd like to be able to do da? with ? being the motion I'm looking for. And if the cursor in my example above is within {} say on 3 I'd delete just the {} but if my cursor was on b I'd delete the [] block, etc.

3 Answers 3


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
    call setpos('.', current_pos) " restore init_pos

  " 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"
    if cnt > 0
      call search('.', 'bW') " previous char

  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"

  " Adjusting the extremities
  if a:inner
    call search('.', 'b')
    normal! o
    call search('.')
    normal! o
" 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.

  • I get a syntax error with your code: 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. Commented Dec 21, 2010 at 20:29
  • Does you vim support dictionaries ? If yes, what happens if you add set cpo&vim at the begining of the script -- which was tested and developped on a vim 7.2.148 on ... Windows XP. (I'm a bit tired of this scattering of the vim community, see the comments on this answer stackoverflow.com/questions/4488979/…) Commented Dec 21, 2010 at 20:55
  • Thanks! How do I invoke it? I tried using b for all blocks but it still selects only () type of block. Do I have to call it differently, or did I install it wrong? Commented Dec 26, 2010 at 10:51
  • ib already means something. You use this one with i% or a% (see the mappings) => di%, va%i%, c2a%, etc Commented Dec 26, 2010 at 13:46

Not by default, but there may be some mechanism to add that functionality. In visual.txt, the section about operating on the visual area, it has this:

The objects that can be used are:
    aw      a word (with white space)                       |v_aw|
    iw      inner word                                      |v_iw|
    aW      a WORD (with white space)                       |v_aW|
    iW      inner WORD                                      |v_iW|
    as      a sentence (with white space)                   |v_as|
    is      inner sentence                                  |v_is|
    ap      a paragraph (with white space)                  |v_ap|
    ip      inner paragraph                                 |v_ip|
    ab      a () block (with parenthesis)                   |v_ab|
    ib      inner () block                                  |v_ib|
    aB      a {} block (with braces)                        |v_aB|
    iB      inner {} block                                  |v_iB|
    at      a <tag> </tag> block (with tags)                |v_at|
    it      inner <tag> </tag> block                        |v_it|
    a<      a <> block (with <>)                            |v_a<|
    i<      inner <> block                                  |v_i<|
    a[      a [] block (with [])                            |v_a[|
    i[      inner [] block                                  |v_i[|
    a"      a double quoted string (with quotes)            |v_aquote|
    a'      a single quoted string (with quotes)            |v_a'|
    i'      inner simple quoted string                      |v_i'|
    a`      a string in backticks (with backticks)          |v_a`|
    i`      inner string in backticks                       |v_i`|

There's a vim addon called textobj-user that supports .. um, something like this. Actually I'm not sure I understood what you're looking for, but I think that addon is meant to make it more convenient to write an addon to implement what you want.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .