# HG changeset patch # User Christian Brabandt # Date 1709157603 -3600 # Node ID d06ffca914416df19231f003982bbea6fc44141a # Parent 4b3ffb6965eca7749b955c139358de6cae98e3f2 patch 9.1.0142: getregion() can be improved Commit: https://github.com/vim/vim/commit/19b718828d8d5fab52d94c6cdba694641879ab38 Author: Shougo Matsushita Date: Wed Feb 28 22:48:12 2024 +0100 patch 9.1.0142: getregion() can be improved Problem: getregion() can be improved (after v9.1.120) Solution: change getregion() implementation to use pos as lists and one optional {opt} dictionary (Shougo Matsushita) Note: The following is a breaking change! Currently, the getregion() function (included as of patch v9.1.120) takes 3 arguments: the first 2 arguments are strings, describing a position, arg3 is the type string. However, that is slightly inflexible, there is no way to specify additional arguments. So let's instead change the function signature to: getregion(pos1, pos2 [, {Dict}]) where both pos1 and pos2 are lists. This is slightly cleaner, and gives us the flexibility to specify additional arguments as key/value pairs to the optional Dict arg. Now it supports the "type" key to specify the selection type (characterwise, blockwise or linewise) and now in addition one can also define the selection type, independently of what the 'selection' option actually is. Technically, this is a breaking change, but since the getregion() Vimscript function is still quite new, this should be fine. closes: #14090 Co-authored-by: zeertzjq Signed-off-by: Shougo Matsushita Signed-off-by: Christian Brabandt diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -1,4 +1,4 @@ -*builtin.txt* For Vim version 9.1. Last change: 2024 Feb 25 +*builtin.txt* For Vim version 9.1. Last change: 2024 Feb 28 VIM REFERENCE MANUAL by Bram Moolenaar @@ -263,7 +263,7 @@ getqflist({what}) Dict get specific qui getreg([{regname} [, 1 [, {list}]]]) String or List contents of a register getreginfo([{regname}]) Dict information about a register -getregion({pos1}, {pos2}, {type}) +getregion({pos1}, {pos2} [, {opts}]) List get the text from {pos1} to {pos2} getregtype([{regname}]) String type of a register getscriptinfo([{opts}]) List list of sourced scripts @@ -4271,14 +4271,25 @@ getreginfo([{regname}]) *getreginfo( Can also be used as a |method|: > GetRegname()->getreginfo() -getregion({pos1}, {pos2}, {type}) *getregion()* - Returns the list of strings from {pos1} to {pos2} as if it's - selected in visual mode of {type}. - For possible values of {pos1} and {pos2} see |line()|. - {type} is the selection type: - "v" for |characterwise| mode - "V" for |linewise| mode - "" for |blockwise-visual| mode +getregion({pos1}, {pos2} [, {opts}]) *getregion()* + Returns the list of strings from {pos1} to {pos2} in current + buffer. + + {pos1} and {pos2} must both be |List|s with four numbers. + See |getpos()| for the format of the list. + + The optional argument {opts} is a Dict and supports the + following items: + + type Specify the selection type + (default: "v"): + "v" for |characterwise| mode + "V" for |linewise| mode + "" for |blockwise-visual| mode + + exclusive If |true|, use exclusive selection + for the end position 'selection'. + You can get the last selection type by |visualmode()|. If Visual mode is active, use |mode()| to get the Visual mode (e.g., in a |:vmap|). @@ -4296,19 +4307,16 @@ getregion({pos1}, {pos2}, {type}) *get - If the selection starts or ends in the middle of a multibyte character, it is not included but its selected part is substituted with spaces. - - If {pos1} or {pos2} equals "v" (see |line()|) and it is not in - |visual-mode|, an empty list is returned. - - If {pos1}, {pos2} or {type} is an invalid string, an empty - list is returned. - - If {pos1} or {pos2} is a mark in different buffer, an empty + - If {pos1} or {pos2} is not current in the buffer, an empty list is returned. Examples: > :xnoremap - \ echow getregion('v', '.', mode()) -< - Can also be used as a |method|: > - '.'->getregion("'a", 'v') + \ echow getregion( + \ getpos('v'), getpos('.'), #{ type: mode() }) +< + Can also be used as a |method|: > + getpos('.')->getregion(getpos("'a")) < getregtype([{regname}]) *getregtype()* The result is a String, which is type of register {regname}. diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1151,6 +1151,7 @@ static argcheck_T arg3_buffer_string_dic static argcheck_T arg3_dict_number_number[] = {arg_dict_any, arg_number, arg_number}; static argcheck_T arg3_diff[] = {arg_list_string, arg_list_string, arg_dict_any}; static argcheck_T arg3_list_string_dict[] = {arg_list_any, arg_string, arg_dict_any}; +static argcheck_T arg3_list_list_dict[] = {arg_list_any, arg_list_any, arg_dict_any}; static argcheck_T arg3_lnum_number_bool[] = {arg_lnum, arg_number, arg_bool}; static argcheck_T arg3_number[] = {arg_number, arg_number, arg_number}; static argcheck_T arg3_number_any_dict[] = {arg_number, arg_any, arg_dict_any}; @@ -2132,7 +2133,7 @@ static funcentry_T global_functions[] = ret_getreg, f_getreg}, {"getreginfo", 0, 1, FEARG_1, arg1_string, ret_dict_any, f_getreginfo}, - {"getregion", 3, 3, FEARG_1, arg3_string, + {"getregion", 2, 3, FEARG_1, arg3_list_list_dict, ret_list_string, f_getregion}, {"getregtype", 0, 1, FEARG_1, arg1_string, ret_string, f_getregtype}, @@ -5491,41 +5492,43 @@ f_getregion(typval_T *argvars, typval_T int inclusive = TRUE; int fnum = -1; pos_T p1, p2; - pos_T *fp = NULL; - char_u *pos1, *pos2, *type; + char_u *type; + char_u default_type[] = "v"; int save_virtual = -1; int l; int region_type = -1; - int is_visual; + int is_select_exclusive; if (rettv_list_alloc(rettv) == FAIL) return; - if (check_for_string_arg(argvars, 0) == FAIL - || check_for_string_arg(argvars, 1) == FAIL - || check_for_string_arg(argvars, 2) == FAIL) - return; - - // NOTE: var2fpos() returns static pointer. - fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE); - if (fp == NULL || (fnum >= 0 && fnum != curbuf->b_fnum)) - return; - p1 = *fp; - - fp = var2fpos(&argvars[1], TRUE, &fnum, FALSE); - if (fp == NULL || (fnum >= 0 && fnum != curbuf->b_fnum)) - return; - p2 = *fp; - - pos1 = tv_get_string(&argvars[0]); - pos2 = tv_get_string(&argvars[1]); - type = tv_get_string(&argvars[2]); - - is_visual = (pos1[0] == 'v' && pos1[1] == NUL) - || (pos2[0] == 'v' && pos2[1] == NUL); - - if (is_visual && !VIsual_active) - return; + if (check_for_list_arg(argvars, 0) == FAIL + || check_for_list_arg(argvars, 1) == FAIL + || check_for_opt_dict_arg(argvars, 2) == FAIL) + return; + + if (list2fpos(&argvars[0], &p1, &fnum, NULL, FALSE) != OK + || (fnum >= 0 && fnum != curbuf->b_fnum)) + return; + + if (list2fpos(&argvars[1], &p2, &fnum, NULL, FALSE) != OK + || (fnum >= 0 && fnum != curbuf->b_fnum)) + return; + + if (argvars[2].v_type == VAR_DICT) + { + is_select_exclusive = dict_get_bool( + argvars[2].vval.v_dict, "exclusive", *p_sel == 'e'); + type = dict_get_string( + argvars[2].vval.v_dict, "type", FALSE); + if (type == NULL) + type = default_type; + } + else + { + is_select_exclusive = *p_sel == 'e'; + type = default_type; + } if (type[0] == 'v' && type[1] == NUL) region_type = MCHAR; @@ -5539,6 +5542,10 @@ f_getregion(typval_T *argvars, typval_T save_virtual = virtual_op; virtual_op = virtual_active(); + // NOTE: Adjust is needed. + p1.col--; + p2.col--; + if (!LT_POS(p1, p2)) { // swap position @@ -5552,7 +5559,7 @@ f_getregion(typval_T *argvars, typval_T if (region_type == MCHAR) { // handle 'selection' == "exclusive" - if (*p_sel == 'e' && !EQUAL_POS(p1, p2)) + if (is_select_exclusive && !EQUAL_POS(p1, p2)) { if (p2.coladd > 0) p2.coladd--; @@ -5590,7 +5597,7 @@ f_getregion(typval_T *argvars, typval_T oa.start = p1; oa.end = p2; oa.start_vcol = MIN(sc1, sc2); - if (*p_sel == 'e' && ec1 < sc2 && 0 < sc2 && ec2 > ec1) + if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) oa.end_vcol = sc2 - 1; else oa.end_vcol = MAX(ec1, ec2); diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -5198,12 +5198,11 @@ def Test_passing_type_to_builtin() enddef def Test_getregion() - assert_equal(['x'], getregion('.', '.', 'v')->map((_, _) => 'x')) - - v9.CheckDefAndScriptFailure(['getregion(10, ".", "v")'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) - assert_equal([''], getregion('.', '.', 'v')) - v9.CheckDefExecFailure(['getregion("a", ".", "v")'], 'E1209:') - v9.CheckDefExecAndScriptFailure(['getregion("", ".", "v")'], 'E1209: Invalid value for a line number') + assert_equal(['x'], getregion(getpos('.'), getpos('.'))->map((_, _) => 'x')) + + v9.CheckDefAndScriptFailure(['getregion(10, getpos("."))'], ['E1013: Argument 1: type mismatch, expected list but got number', 'E1211: List required for argument 1']) + assert_equal([''], getregion(getpos('.'), getpos('.'))) + v9.CheckDefExecFailure(['getregion(getpos("a"), getpos("."))'], 'E1209:') enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1638,80 +1638,113 @@ func Test_visual_getregion() " Visual mode call cursor(1, 1) call feedkeys("\vjl", 'tx') - call assert_equal(['one', 'tw'], 'v'->getregion('.', 'v')) - call assert_equal(['one', 'tw'], '.'->getregion('v', 'v')) - call assert_equal(['o'], 'v'->getregion('v', 'v')) - call assert_equal(['w'], '.'->getregion('.', 'v')) - call assert_equal(['one', 'two'], '.'->getregion('v', 'V')) - call assert_equal(['on', 'tw'], '.'->getregion('v', "\")) + call assert_equal(['one', 'tw'], + \ 'v'->getpos()->getregion(getpos('.'))) + call assert_equal(['one', 'tw'], + \ '.'->getpos()->getregion(getpos('v'))) + call assert_equal(['o'], + \ 'v'->getpos()->getregion(getpos('v'))) + call assert_equal(['w'], + \ '.'->getpos()->getregion(getpos('.'), #{ type: 'v' })) + call assert_equal(['one', 'two'], + \ getpos('.')->getregion(getpos('v'), #{ type: 'V' })) + call assert_equal(['on', 'tw'], + \ getpos('.')->getregion(getpos('v'), #{ type: "\" })) " Line visual mode call cursor(1, 1) call feedkeys("\Vl", 'tx') - call assert_equal(['one'], getregion('v', '.', 'V')) - call assert_equal(['one'], getregion('.', 'v', 'V')) - call assert_equal(['one'], getregion('v', 'v', 'V')) - call assert_equal(['one'], getregion('.', '.', 'V')) - call assert_equal(['on'], '.'->getregion('v', 'v')) - call assert_equal(['on'], '.'->getregion('v', "\")) + call assert_equal(['one'], + \ getregion(getpos('v'), getpos('.'), #{ type: 'V' })) + call assert_equal(['one'], + \ getregion(getpos('.'), getpos('v'), #{ type: 'V' })) + call assert_equal(['one'], + \ getregion(getpos('v'), getpos('v'), #{ type: 'V' })) + call assert_equal(['one'], + \ getregion(getpos('.'), getpos('.'), #{ type: 'V' })) + call assert_equal(['on'], + \ getpos('.')->getregion(getpos('v'), #{ type: 'v' })) + call assert_equal(['on'], + \ getpos('.')->getregion(getpos('v'), #{ type: "\" })) " Block visual mode call cursor(1, 1) call feedkeys("\\ll", 'tx') - call assert_equal(['one'], getregion('v', '.', "\")) - call assert_equal(['one'], getregion('.', 'v', "\")) - call assert_equal(['o'], getregion('v', 'v', "\")) - call assert_equal(['e'], getregion('.', '.', "\")) - call assert_equal(['one'], '.'->getregion('v', 'V')) - call assert_equal(['one'], '.'->getregion('v', 'v')) + call assert_equal(['one'], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) + call assert_equal(['one'], + \ getregion(getpos('.'), getpos('v'), #{ type: "\" })) + call assert_equal(['o'], + \ getregion(getpos('v'), getpos('v'), #{ type: "\" })) + call assert_equal(['e'], + \ getregion(getpos('.'), getpos('.'), #{ type: "\" })) + call assert_equal(['one'], + \ '.'->getpos()->getregion(getpos('v'), #{ type: 'V' })) + call assert_equal(['one'], + \ '.'->getpos()->getregion(getpos('v'), #{ type: 'v' })) " Using Marks call setpos("'a", [0, 2, 3, 0]) call cursor(1, 1) - call assert_equal(['one', 'two'], "'a"->getregion('.', 'v')) - call assert_equal(['one', 'two'], "."->getregion("'a", 'v')) - call assert_equal(['one', 'two'], "."->getregion("'a", 'V')) - call assert_equal(['two'], "'a"->getregion("'a", 'V')) - call assert_equal(['one', 'two'], "."->getregion("'a", "\")) + call assert_equal(['one', 'two'], + \ "'a"->getpos()->getregion(getpos('.'), #{ type: 'v' })) + call assert_equal(['one', 'two'], + \ "."->getpos()->getregion(getpos("'a"), #{ type: 'v' })) + call assert_equal(['one', 'two'], + \ "."->getpos()->getregion(getpos("'a"), #{ type: 'V' })) + call assert_equal(['two'], + \ "'a"->getpos()->getregion(getpos("'a"), #{ type: 'V' })) + call assert_equal(['one', 'two'], + \ "."->getpos()->getregion(getpos("'a"), #{ type: "\" })) + + " Using List + call cursor(1, 1) + call assert_equal(['one', 'two'], + \ [0, 2, 3, 0]->getregion(getpos('.'), #{ type: 'v' })) + call assert_equal(['one', 'two'], + \ '.'->getpos()->getregion([0, 2, 3, 0], #{ type: 'v' })) + call assert_equal(['one', 'two'], + \ '.'->getpos()->getregion([0, 2, 3, 0], #{ type: 'V' })) + call assert_equal(['two'], + \ [0, 2, 3, 0]->getregion([0, 2, 3, 0], #{ type: 'V' })) + call assert_equal(['one', 'two'], + \ '.'->getpos()->getregion([0, 2, 3, 0], #{ type: "\" })) " Multiline with line visual mode call cursor(1, 1) call feedkeys("\Vjj", 'tx') - call assert_equal(['one', 'two', 'three'], getregion('v', '.', 'V')) + call assert_equal(['one', 'two', 'three'], + \ getregion(getpos('v'), getpos('.'), #{ type: 'V' })) " Multiline with block visual mode call cursor(1, 1) call feedkeys("\\jj", 'tx') - call assert_equal(['o', 't', 't'], getregion('v', '.', "\")) + call assert_equal(['o', 't', 't'], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) call cursor(1, 1) call feedkeys("\\jj$", 'tx') - call assert_equal(['one', 'two', 'three'], getregion('v', '.', "\")) + call assert_equal(['one', 'two', 'three'], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) " 'virtualedit' set virtualedit=all call cursor(1, 1) call feedkeys("\\10ljj$", 'tx') call assert_equal(['one ', 'two ', 'three '], - \ getregion('v', '.', "\")) + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) set virtualedit& " Invalid position call cursor(1, 1) call feedkeys("\vjj$", 'tx') - call assert_fails("call getregion(1, 2, 'v')", 'E1174:') - call assert_fails("call getregion('.', {}, 'v')", 'E1174:') - call assert_equal([], getregion('', '.', 'v')) - call assert_equal([], getregion('.', '.', '')) - call feedkeys("\", 'tx') - call assert_equal([], getregion('v', '.', 'v')) + call assert_fails("call getregion(1, 2)", 'E1211:') + call assert_fails("call getregion(getpos('.'), {})", 'E1211:') + call assert_equal([], getregion(getpos('.'), getpos('.'), #{ type: '' })) - " using an unset mark - call assert_equal([], "'z"->getregion(".", 'V')) " using the wrong type - call assert_fails(':echo "."->getregion([],"V")', 'E1174:') - call assert_fails(':echo "."->getregion("$", {})', 'E1174:') - call assert_fails(':echo [0, 1, 1, 0]->getregion("$", "v")', 'E1174:') + call assert_fails(':echo "."->getpos()->getregion("$", [])', 'E1211:') + " using a mark in another buffer new let newbuf = bufnr() @@ -1719,8 +1752,8 @@ func Test_visual_getregion() normal! GmA wincmd p call assert_equal([newbuf, 10, 1, 0], getpos("'A")) - call assert_equal([], getregion(".", "'A", 'v')) - call assert_equal([], getregion("'A", ".", 'v')) + call assert_equal([], getregion(getpos('.'), getpos("'A"), #{ type: 'v' })) + call assert_equal([], getregion(getpos("'A"), getpos('.'), #{ type: 'v' })) exe newbuf .. 'bwipe!' bwipe! @@ -1734,26 +1767,47 @@ func Test_visual_getregion() call cursor(1, 3) call feedkeys("\\ljj", 'xt') call assert_equal(['cd', "\u00ab ", '34'], - \ getregion('v', '.', "\")) + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) call cursor(1, 4) call feedkeys("\\ljj", 'xt') call assert_equal(['de', "\U0001f1e7", '45'], - \ getregion('v', '.', "\")) + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) call cursor(1, 5) call feedkeys("\\jj", 'xt') - call assert_equal(['e', ' ', '5'], getregion('v', '.', "\")) + call assert_equal(['e', ' ', '5'], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) call cursor(1, 1) call feedkeys("\vj", 'xt') - call assert_equal(['abcdefghijk«', "\U0001f1e6"], getregion('v', '.', "v")) + call assert_equal(['abcdefghijk«', "\U0001f1e6"], + \ getregion(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]) call cursor(1, 1) - call assert_equal(['ghijk', '🇨«🇩'], getregion("'a", "'b", "\")) - call assert_equal(['k«', '🇦«🇧«🇨'], getregion("'a", "'b", "v")) - call assert_equal(['k«'], getregion("'a", "'c", "v")) + call assert_equal(['ghijk', '🇨«🇩'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: "\" })) + call assert_equal(['k«', '🇦«🇧«🇨'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: 'v' })) + call assert_equal(['k«'], + \ getregion(getpos("'a"), getpos("'c"), #{ type: 'v' })) + + " use inclusive selection, although 'selection' is exclusive + call setpos("'a", [0, 1, 11, 0]) + call setpos("'b", [0, 1, 1, 0]) + call assert_equal(['abcdefghijk'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: "\", exclusive: v:false })) + call assert_equal(['abcdefghij'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: "\", exclusive: v:true })) + call assert_equal(['abcdefghijk'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: 'v', exclusive: 0 })) + call assert_equal(['abcdefghij'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: 'v', exclusive: 1 })) + call assert_equal(['abcdefghijk«'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: 'V', exclusive: 0 })) + call assert_equal(['abcdefghijk«'], + \ getregion(getpos("'a"), getpos("'b"), #{ type: 'V', exclusive: 1 })) bwipe! @@ -1763,31 +1817,71 @@ func Test_visual_getregion() call setline(1, ["a\tc", "x\tz", '', '']) call cursor(1, 1) call feedkeys("\v2l", 'xt') - call assert_equal(["a\t"], getregion('v', '.', 'v')) + call assert_equal(["a\t"], + \ getregion(getpos('v'), getpos('.'), #{ type: 'v' })) call cursor(1, 1) call feedkeys("\v$G", 'xt') - call assert_equal(["a\tc", "x\tz", ''], getregion('v', '.', 'v')) + call assert_equal(["a\tc", "x\tz", ''], + \ getregion(getpos('v'), getpos('.'), #{ type: 'v' })) call cursor(1, 1) call feedkeys("\v$j", 'xt') - call assert_equal(["a\tc", "x\tz"], getregion('v', '.', 'v')) + call assert_equal(["a\tc", "x\tz"], + \ getregion(getpos('v'), getpos('.'), #{ type: 'v' })) call cursor(1, 1) call feedkeys("\\$j", 'xt') - call assert_equal(["a\tc", "x\tz"], getregion('v', '.', "\")) + call assert_equal(["a\tc", "x\tz"], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) call cursor(1, 1) call feedkeys("\\$G", 'xt') - call assert_equal(["a", "x", '', ''], getregion('v', '.', "\")) + call assert_equal(["a", "x", '', ''], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) call cursor(1, 1) call feedkeys("\wv2j", 'xt') - call assert_equal(["c", "x\tz"], getregion('v', '.', 'v')) + call assert_equal(["c", "x\tz"], + \ getregion(getpos('v'), getpos('.'), #{ type: 'v' })) + set selection& + + " Exclusive selection 2 + new + call setline(1, ["a\tc", "x\tz", '', '']) + call cursor(1, 1) + call feedkeys("\v2l", 'xt') + call assert_equal(["a\t"], + \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true })) + call cursor(1, 1) + call feedkeys("\v$G", 'xt') + call assert_equal(["a\tc", "x\tz", ''], + \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true })) + call cursor(1, 1) + call feedkeys("\v$j", 'xt') + call assert_equal(["a\tc", "x\tz"], + \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true })) + call cursor(1, 1) + call feedkeys("\\$j", 'xt') + call assert_equal(["a\tc", "x\tz"], + \ getregion(getpos('v'), getpos('.'), + \ #{ exclusive: v:true, type: "\" })) + call cursor(1, 1) + call feedkeys("\\$G", 'xt') + call assert_equal(["a", "x", '', ''], + \ getregion(getpos('v'), getpos('.'), + \ #{ exclusive: v:true, type: "\" })) + call cursor(1, 1) + call feedkeys("\wv2j", 'xt') + call assert_equal(["c", "x\tz"], + \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true })) " virtualedit + set selection=exclusive set virtualedit=all call cursor(1, 1) call feedkeys("\2lv2lj", 'xt') - call assert_equal([' c', 'x '], getregion('v', '.', 'v')) + call assert_equal([' c', 'x '], + \ getregion(getpos('v'), getpos('.'), #{ type: 'v' })) call cursor(1, 1) call feedkeys("\2l\2l2j", 'xt') - call assert_equal([' ', ' ', ' '], getregion('v', '.', "\")) + call assert_equal([' ', ' ', ' '], + \ getregion(getpos('v'), getpos('.'), #{ type: "\" })) set virtualedit& set selection& diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 142, +/**/ 141, /**/ 140,