vim-patch:9.1.0007: can select empty inner text blocks

Problem:  can select empty inner text blocks
          (laurentalacoque)
Solution: make selecting empty inner text blocks an error

textobjects: Make selecting inner empty blocks an error

fixes: vim/vim#13514
closes: vim/vim#13523

ad4d7f446d

Co-authored-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq 2024-01-06 06:19:19 +08:00
parent 52e6059415
commit f38f86b1ad
3 changed files with 126 additions and 8 deletions

View File

@ -578,7 +578,8 @@ i] *v_i]* *v_i[* *i]* *i[*
i[ "inner [] block", select [count] '[' ']' blocks. This i[ "inner [] block", select [count] '[' ']' blocks. This
goes backwards to the [count] unclosed '[', and finds goes backwards to the [count] unclosed '[', and finds
the matching ']'. The enclosed text is selected, the matching ']'. The enclosed text is selected,
excluding the '[' and ']'. The |cpo-M| option flag excluding the '[' and ']'. It's an error to select an
empty inner block like "[]". The |cpo-M| option flag
is used to handle escaped brackets. is used to handle escaped brackets.
When used in Visual mode it is made charwise. When used in Visual mode it is made charwise.
@ -596,7 +597,8 @@ i( *vib* *v_ib* *v_i(* *ib*
ib "inner block", select [count] blocks, from "[count] [(" ib "inner block", select [count] blocks, from "[count] [("
to the matching ')', excluding the '(' and ')' (see to the matching ')', excluding the '(' and ')' (see
|[(|). If the cursor is not inside a () block, then |[(|). If the cursor is not inside a () block, then
find the next "(". The |cpo-M| option flag find the next "(". It's an error to select an empty
inner block like "()". The |cpo-M| option flag
is used to handle escaped parenthesis. is used to handle escaped parenthesis.
When used in Visual mode it is made charwise. When used in Visual mode it is made charwise.
@ -610,8 +612,9 @@ a< "a <> block", select [count] <> blocks, from the
i> *v_i>* *v_i<* *i>* *i<* i> *v_i>* *v_i<* *i>* *i<*
i< "inner <> block", select [count] <> blocks, from i< "inner <> block", select [count] <> blocks, from
the [count]'th unmatched '<' backwards to the matching the [count]'th unmatched '<' backwards to the matching
'>', excluding the '<' and '>'. The |cpo-M| option flag '>', excluding the '<' and '>'. It's an error to
is used to handle escaped '<' and '>'. select an empty inner block like "<>". The |cpo-M|
option flag is used to handle escaped '<' and '>'.
When used in Visual mode it is made charwise. When used in Visual mode it is made charwise.
*v_at* *at* *v_at* *at*
@ -640,7 +643,8 @@ i} *v_i}* *i}* *i{*
i{ *v_iB* *v_i{* *iB* i{ *v_iB* *v_i{* *iB*
iB "inner Block", select [count] Blocks, from `[count] [{` iB "inner Block", select [count] Blocks, from `[count] [{`
to the matching "}", excluding the "{" and "}" (see to the matching "}", excluding the "{" and "}" (see
|[{|). The |cpo-M| option flag is used to handle |[{|). It"s an error to select an empty inner block
like "{}". The |cpo-M| option flag is used to handle
escaped braces. escaped braces.
When used in Visual mode it is made charwise. When used in Visual mode it is made charwise.

View File

@ -955,6 +955,12 @@ int current_block(oparg_T *oap, int count, bool include, int what, int other)
} }
} }
if (equalpos(start_pos, *end_pos)) {
// empty block like this: ()
// there is no inner block to select, abort
return FAIL;
}
// In Visual mode, when the resulting area is not bigger than what we // In Visual mode, when the resulting area is not bigger than what we
// started with, extend it to the next block, and then exclude again. // started with, extend it to the next block, and then exclude again.
// Don't try to expand the area if the area is empty. // Don't try to expand the area if the area is empty.

View File

@ -402,7 +402,7 @@ func Test_paragraph()
call assert_beeps("normal Vipip") call assert_beeps("normal Vipip")
exe "normal \<C-C>" exe "normal \<C-C>"
close! bw!
endfunc endfunc
" Tests for text object aw " Tests for text object aw
@ -608,7 +608,7 @@ func Test_textobj_quote()
normal $hhyi" normal $hhyi"
call assert_equal('bar', @") call assert_equal('bar', @")
close! bw!
endfunc endfunc
" Test for i(, i<, etc. when cursor is in front of a block " Test for i(, i<, etc. when cursor is in front of a block
@ -640,7 +640,115 @@ func Test_textobj_find_paren_forward()
normal 0di) normal 0di)
call assert_equal('foo ()', getline(1)) call assert_equal('foo ()', getline(1))
close! bw!
endfunc
func Test_inner_block_empty_paren()
new
call setline(1, ["(text)()", "", "(text)(", ")", "", "()()"])
" Example 1
call cursor(1, 1)
let @" = ''
call assert_beeps(':call feedkeys("0f(viby","xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('(', @")
" Example 2
call cursor(3, 1)
let @" = ''
call assert_beeps('call feedkeys("0f(viby", "xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('(', @")
" Example 3
call cursor(6, 1)
let @" = ''
call assert_beeps('call feedkeys("0f(viby", "xt")')
call assert_equal(3, getpos('.')[2])
call assert_equal('(', @")
bwipe!
endfunc
func Test_inner_block_empty_bracket()
new
call setline(1, ["[text][]", "", "[text][", "]", "", "[][]"])
" Example 1
call cursor(1, 1)
let @" = ''
call assert_beeps(':call feedkeys("0f[viby","xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('[', @")
" Example 2
call cursor(3, 1)
let @" = ''
call assert_beeps('call feedkeys("0f[viby", "xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('[', @")
" Example 3
call cursor(6, 1)
let @" = ''
call assert_beeps('call feedkeys("0f[viby", "xt")')
call assert_equal(3, getpos('.')[2])
call assert_equal('[', @")
bwipe!
endfunc
func Test_inner_block_empty_brace()
new
call setline(1, ["{text}{}", "", "{text}{", "}", "", "{}{}"])
" Example 1
call cursor(1, 1)
let @" = ''
call assert_beeps(':call feedkeys("0f{viby","xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('{', @")
" Example 2
call cursor(3, 1)
let @" = ''
call assert_beeps('call feedkeys("0f{viby", "xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('{', @")
" Example 3
call cursor(6, 1)
let @" = ''
call assert_beeps('call feedkeys("0f{viby", "xt")')
call assert_equal(3, getpos('.')[2])
call assert_equal('{', @")
bwipe!
endfunc
func Test_inner_block_empty_lessthan()
new
call setline(1, ["<text><>", "", "<text><", ">", "", "<><>"])
" Example 1
call cursor(1, 1)
let @" = ''
call assert_beeps(':call feedkeys("0f<viby","xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('<', @")
" Example 2
call cursor(3, 1)
let @" = ''
call assert_beeps('call feedkeys("0f<viby", "xt")')
call assert_equal(7, getpos('.')[2])
call assert_equal('<', @")
" Example 3
call cursor(6, 1)
let @" = ''
call assert_beeps('call feedkeys("0f<viby", "xt")')
call assert_equal(3, getpos('.')[2])
call assert_equal('<', @")
bwipe!
endfunc endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab