aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/motion.txt14
-rw-r--r--src/nvim/textobject.c6
-rw-r--r--test/old/testdir/test_textobjects.vim114
3 files changed, 126 insertions, 8 deletions
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index b72dd8d39c..03fe5c7b81 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -578,7 +578,8 @@ i] *v_i]* *v_i[* *i]* *i[*
i[ "inner [] block", select [count] '[' ']' blocks. This
goes backwards to the [count] unclosed '[', and finds
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.
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] [("
to the matching ')', excluding the '(' and ')' (see
|[(|). 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.
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< "inner <> block", select [count] <> blocks, from
the [count]'th unmatched '<' backwards to the matching
- '>', excluding the '<' and '>'. The |cpo-M| option flag
- is used to handle escaped '<' and '>'.
+ '>', excluding the '<' and '>'. It's an error to
+ 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.
*v_at* *at*
@@ -640,7 +643,8 @@ i} *v_i}* *i}* *i{*
i{ *v_iB* *v_i{* *iB*
iB "inner Block", select [count] Blocks, from `[count] [{`
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.
When used in Visual mode it is made charwise.
diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c
index 3d8e7c9901..3e696167e2 100644
--- a/src/nvim/textobject.c
+++ b/src/nvim/textobject.c
@@ -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
// started with, extend it to the next block, and then exclude again.
// Don't try to expand the area if the area is empty.
diff --git a/test/old/testdir/test_textobjects.vim b/test/old/testdir/test_textobjects.vim
index f21d6fcb99..72c7338a96 100644
--- a/test/old/testdir/test_textobjects.vim
+++ b/test/old/testdir/test_textobjects.vim
@@ -402,7 +402,7 @@ func Test_paragraph()
call assert_beeps("normal Vipip")
exe "normal \<C-C>"
- close!
+ bw!
endfunc
" Tests for text object aw
@@ -608,7 +608,7 @@ func Test_textobj_quote()
normal $hhyi"
call assert_equal('bar', @")
- close!
+ bw!
endfunc
" 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)
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
" vim: shiftwidth=2 sts=2 expandtab