ブラケットタイプのモーションをブロックしますか?


8

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}]
      a)

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

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.


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.
Gilles 'SO- stop being evil'

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/…)
Luc Hermitte

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?
Goran Jovic

ib already means something. You use this one with i% or a% (see the mappings) => di%, va%i%, c2a%, etc
Luc Hermitte

1

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`|

0

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.

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.