diff --git a/README.md b/README.md index f15db09..e5f62a9 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,11 @@ Note too that the `ar` and `ir` text objects always position your cursor on the `end` keyword. If you want to move to the top of the selection, you can do so with the `o` key. +By default `ir` ignores middle keywords like `else` and `when`, but you can have +`ir` acknowledge them by putting this in your .vimrc + + let g:textobj_rubyblock_mids = 1 + Limitations ----------- diff --git a/plugin/textobj/rubyblock.vim b/plugin/textobj/rubyblock.vim index e0e5ad1..07520f1 100644 --- a/plugin/textobj/rubyblock.vim +++ b/plugin/textobj/rubyblock.vim @@ -13,11 +13,18 @@ call textobj#user#plugin('rubyblock', { " Misc. "{{{1 let s:comment_escape = '\v^[^#]*' -let s:block_openers = '\zs(||||)' +let s:block_openers = '\zs(||||||' +let s:block_openers .= '||||)' let s:start_pattern = s:comment_escape . s:block_openers +let s:mid_pattern = s:comment_escape +let s:mid_pattern .= '\zs(||||)' let s:end_pattern = s:comment_escape . '\zs' let s:skip_pattern = 'getline(".") =~ "\\v\\S\\s<(if|unless)>\\s\\S"' +if !exists('g:textobj_rubyblock_mids') + let g:textobj_rubyblock_mids = 0 +endif + function! s:select_a() let s:flags = 'W' @@ -37,15 +44,35 @@ function! s:select_i() let s:flags = 'cW' endif - call searchpair(s:start_pattern,'',s:end_pattern, s:flags, s:skip_pattern) + let l:mid = '' + if g:textobj_rubyblock_mids + let l:mid = s:mid_pattern + endif + + call searchpair(s:start_pattern,l:mid,s:end_pattern, s:flags, s:skip_pattern) " Move up one line, and save position normal k^ let end_pos = getpos('.') - " Move down again, jump to match, then down one line and save position - normal j^%j - let start_pos = getpos('.') + if g:textobj_rubyblock_mids + " Move down again, find match right before, and save position + normal j^ + let l:last_position = getpos('.') + let l:start_line = l:last_position[1] + normal % + while getpos('.')[1] != l:start_line + let l:last_position = getpos('.') + normal % + endwhile + call setpos('.', l:last_position) + normal j^ + let start_pos = getpos('.') + else + " Move down again, jump to match, then down one line and save position + normal j^%j + let start_pos = getpos('.') + endif return ['V', start_pos, end_pos] endfunction diff --git a/t/examples.rb b/t/examples.rb index 9dbd0ad..fe5c03f 100644 --- a/t/examples.rb +++ b/t/examples.rb @@ -65,3 +65,28 @@ def hello bar end +def method_with_while + var1 = 1 + i = 0 + while i < 10 + i += 1 + end + var2 = 2 +end + +def method_with_unless + var1 = 1 + unless condition + puts 'foo' + end + var2 = 2 +end + +def method_with_if_else + if condition + foo = 'foo' + bar = 'bar' + else + baz = 'baz' + end +end diff --git a/t/rubyblock_test.vim b/t/rubyblock_test.vim index dd55ffa..4d2b355 100644 --- a/t/rubyblock_test.vim +++ b/t/rubyblock_test.vim @@ -86,6 +86,47 @@ describe '(textobj-rubyblock-a)' end +describe 'nested while and unless blocks' + + before + silent tabnew t/examples.rb + end + + after + silent tabclose + end + + it 'ignores nested while and unless blocks' + Expect SelectAroundFrom(69, '^') ==# [69, 68, 75] + Expect SelectAroundFrom(78, '^') ==# [78, 77, 83] + end + +end + +describe 'g:textobj_rubyblock_mids' + before + silent tabnew t/examples.rb + end + + after + silent tabclose + end + + context '1' + it 'selects only between mids' + let g:textobj_rubyblock_mids = 1 + Expect SelectInsideFrom(87, '^') ==# [87, 87, 88] + end + end + + context '0' + it 'ignores mids' + let g:textobj_rubyblock_mids = 0 + Expect SelectInsideFrom(87, '^') ==# [87, 87, 90] + end + end +end + describe '(textobj-rubyblock-i)' before