diff options
-rw-r--r-- | runtime/doc/builtin.txt | 4 | ||||
-rw-r--r-- | runtime/lua/vim/_meta/vimfn.lua | 4 | ||||
-rw-r--r-- | src/nvim/eval.lua | 4 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 20 | ||||
-rw-r--r-- | src/nvim/ops.c | 7 | ||||
-rw-r--r-- | test/old/testdir/test_visual.vim | 59 |
6 files changed, 81 insertions, 17 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index e0921cf477..2c1c6675c1 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -2985,8 +2985,8 @@ getregionpos({pos1}, {pos2} [, {opts}]) *getregionpos()* the offset in screen columns from the start of the character. E.g., a position within a <Tab> or after the last character. If the "off" number of an ending position is non-zero, it is - the character's number of cells included in the selection, - otherwise the whole character is included. + the offset of the character's first cell not included in the + selection, otherwise all its cells are included. getregtype([{regname}]) *getregtype()* The result is a String, which is type of register {regname}. diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index dee65a40c7..e00b2e6acd 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3596,8 +3596,8 @@ function vim.fn.getregion(pos1, pos2, opts) end --- the offset in screen columns from the start of the character. --- E.g., a position within a <Tab> or after the last character. --- If the "off" number of an ending position is non-zero, it is ---- the character's number of cells included in the selection, ---- otherwise the whole character is included. +--- the offset of the character's first cell not included in the +--- selection, otherwise all its cells are included. --- --- @param pos1 table --- @param pos2 table diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 58f2ac0acf..b377643917 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -4433,8 +4433,8 @@ M.funcs = { the offset in screen columns from the start of the character. E.g., a position within a <Tab> or after the last character. If the "off" number of an ending position is non-zero, it is - the character's number of cells included in the selection, - otherwise the whole character is included. + the offset of the character's first cell not included in the + selection, otherwise all its cells are included. ]=], name = 'getregionpos', params = { { 'pos1', 'table' }, { 'pos2', 'table' }, { 'opts', 'table' } }, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 1d01f3ad98..7453bbb601 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3041,7 +3041,6 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr } for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { - struct block_def bd; pos_T ret_p1, ret_p2; if (region_type == kMTLineWise) { @@ -3050,19 +3049,34 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr ret_p2.col = MAXCOL; ret_p2.coladd = 0; } else { + struct block_def bd; + if (region_type == kMTBlockWise) { block_prep(&oa, &bd, lnum, false); } else { charwise_block_prep(p1, p2, &bd, lnum, inclusive); } - if (bd.startspaces > 0) { + + if (bd.is_oneChar) { // selection entirely inside one char + if (region_type == kMTBlockWise) { + ret_p1.col = bd.textcol; + ret_p1.coladd = bd.start_char_vcols - (bd.start_vcol - oa.start_vcol); + } else { + ret_p1.col = p1.col + 1; + ret_p1.coladd = p1.coladd; + } + } else if (bd.startspaces > 0) { ret_p1.col = bd.textcol; ret_p1.coladd = bd.start_char_vcols - bd.startspaces; } else { ret_p1.col = bd.textcol + 1; ret_p1.coladd = 0; } - if (bd.endspaces > 0) { + + if (bd.is_oneChar) { // selection entirely inside one char + ret_p2.col = ret_p1.col; + ret_p2.coladd = ret_p1.coladd + bd.startspaces; + } else if (bd.endspaces > 0) { ret_p2.col = bd.textcol + bd.textlen + 1; ret_p2.coladd = bd.endspaces; } else { diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 707cf5ca9a..5c1e291ac6 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4253,11 +4253,12 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T { colnr_T startcol = 0; colnr_T endcol = MAXCOL; - bool is_oneChar = false; colnr_T cs, ce; char *p = ml_get(lnum); + bdp->startspaces = 0; bdp->endspaces = 0; + bdp->is_oneChar = false; bdp->start_char_vcols = 0; if (lnum == start.lnum) { @@ -4287,7 +4288,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T && utf_head_off(p, p + endcol) == 0)) { if (start.lnum == end.lnum && start.col == end.col) { // Special case: inside a single char - is_oneChar = true; + bdp->is_oneChar = true; bdp->startspaces = end.coladd - start.coladd + inclusive; endcol = startcol; } else { @@ -4300,7 +4301,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T if (endcol == MAXCOL) { endcol = ml_get_len(lnum); } - if (startcol > endcol || is_oneChar) { + if (startcol > endcol || bdp->is_oneChar) { bdp->textlen = 0; } else { bdp->textlen = endcol - startcol + inclusive; diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim index fa82531170..a682455227 100644 --- a/test/old/testdir/test_visual.vim +++ b/test/old/testdir/test_visual.vim @@ -1893,7 +1893,7 @@ func Test_visual_getregion() \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) call assert_equal([ \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 5, 0]], - \ [[bufnr('%'), 2, 10, 1], [bufnr('%'), 2, 10, 0]], + \ [[bufnr('%'), 2, 10, 1], [bufnr('%'), 2, 10, 2]], \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 5, 0]], \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) @@ -1904,6 +1904,7 @@ func Test_visual_getregion() \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + #" characterwise selection with multibyte chars call cursor(1, 1) call feedkeys("\<Esc>vj", 'xt') call assert_equal(['abcdefghijk«', "\U0001f1e6"], @@ -1914,8 +1915,17 @@ func Test_visual_getregion() \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + set selection=exclusive + call feedkeys('l', 'xt') + call assert_equal(['abcdefghijk«', "\U0001f1e6"], + \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) + call assert_equal([ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 13, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 4, 0]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + #" marks on multibyte chars - :set selection=exclusive call setpos("'a", [0, 1, 11, 0]) call setpos("'b", [0, 2, 16, 0]) call setpos("'c", [0, 2, 0, 0]) @@ -2001,6 +2011,7 @@ func Test_visual_getregion() call assert_equal(["c", "x\tz"], \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) set selection& + bwipe! #" Exclusive selection 2 new @@ -2037,7 +2048,24 @@ func Test_visual_getregion() set virtualedit=all call cursor(1, 1) - call feedkeys("\<Esc>2lv2lj", 'xt') + call feedkeys("\<Esc>lv2l", 'xt') + call assert_equal([' '], + \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) + call assert_equal([ + \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 2]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + + call cursor(1, 1) + call feedkeys("\<Esc>2lv2l", 'xt') + call assert_equal([' '], + \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) + call assert_equal([ + \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 3]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + + call feedkeys('j', 'xt') call assert_equal([' c', 'x '], \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) call assert_equal([ @@ -2047,12 +2075,33 @@ func Test_visual_getregion() \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) call cursor(1, 1) + call feedkeys("\<Esc>6l\<C-v>2lj", 'xt') + call assert_equal([' ', ' '], + \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + call assert_equal([ + \ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 2, 7]], + \ [[bufnr('%'), 2, 2, 5], [bufnr('%'), 2, 2, 7]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + + call cursor(1, 1) + call feedkeys("\<Esc>l\<C-v>2l2j", 'xt') + call assert_equal([' ', ' ', ' '], + \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + call assert_equal([ + \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 2, 2]], + \ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 2]], + \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 2]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) + + call cursor(1, 1) call feedkeys("\<Esc>2l\<C-v>2l2j", 'xt') call assert_equal([' ', ' ', ' '], \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" })) call assert_equal([ - \ [[bufnr('%'), 1, 2, 5], [bufnr('%'), 1, 2, 0]], - \ [[bufnr('%'), 2, 2, 5], [bufnr('%'), 2, 2, 0]], + \ [[bufnr('%'), 1, 2, 1], [bufnr('%'), 1, 2, 3]], + \ [[bufnr('%'), 2, 2, 1], [bufnr('%'), 2, 2, 3]], \ [[bufnr('%'), 3, 0, 0], [bufnr('%'), 3, 0, 2]], \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': "\<C-v>" })) |