patch 9.1.0142: getregion() can be improved

Commit: 
https://github.com/vim/vim/commit/19b718828d8d5fab52d94c6cdba694641879ab38
Author: Shougo Matsushita <[email protected]>
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 <[email protected]>
    Signed-off-by: Shougo Matsushita <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 0af9b0e0f..6d1d372cf 100644
--- 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 quickfix 
list properties
 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
-                       "<CTRL-V>" 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
+                           "<CTRL-V>"  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})                       
*getregion()*
                - 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 <CR>
-                       \ <Cmd>echow getregion('v', '.', mode())<CR>
+                       \ <Cmd>echow getregion(
+                       \ getpos('v'), getpos('.'), #{ type: mode() })<CR>
 <
                Can also be used as a |method|: >
-                       '.'->getregion("'a", 'v')
+                       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
index 37010d7ba..b5d8c872e 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -1151,6 +1151,7 @@ static argcheck_T arg3_buffer_string_dict[] = 
{arg_buffer, arg_string, arg_dict_
 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 *rettv)
     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)
+    if (check_for_list_arg(argvars, 0) == FAIL
+           || check_for_list_arg(argvars, 1) == FAIL
+           || check_for_opt_dict_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))
+    if (list2fpos(&argvars[0], &p1, &fnum, NULL, FALSE) != OK
+           || (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))
+    if (list2fpos(&argvars[1], &p2, &fnum, NULL, FALSE) != OK
+           || (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 (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 *rettv)
     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 *rettv)
     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 *rettv)
        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
index e2585d4f6..afb8cb910 100644
--- 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'))
+  assert_equal(['x'], getregion(getpos('.'), getpos('.'))->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')
+  v9.CheckDefAndScriptFailure(['getregion(10, getpos("."))'], ['E1013: 
Argument 1: type mismatch, expected list<any> 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
index 8b434238a..fdc19827b 100644
--- 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("\<ESC>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', "\<C-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: "\<C-v>" }))
 
   " Line visual mode
   call cursor(1, 1)
   call feedkeys("\<ESC>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', "\<C-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: "\<C-v>" }))
 
   " Block visual mode
   call cursor(1, 1)
   call feedkeys("\<ESC>\<C-v>ll", 'tx')
-  call assert_equal(['one'], getregion('v', '.', "\<C-v>"))
-  call assert_equal(['one'], getregion('.', 'v', "\<C-v>"))
-  call assert_equal(['o'], getregion('v', 'v', "\<C-v>"))
-  call assert_equal(['e'], getregion('.', '.', "\<C-v>"))
-  call assert_equal(['one'], '.'->getregion('v', 'V'))
-  call assert_equal(['one'], '.'->getregion('v', 'v'))
+  call assert_equal(['one'],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
+  call assert_equal(['one'],
+        \ getregion(getpos('.'), getpos('v'), #{ type: "\<C-v>" }))
+  call assert_equal(['o'],
+        \ getregion(getpos('v'), getpos('v'), #{ type: "\<C-v>" }))
+  call assert_equal(['e'],
+        \ getregion(getpos('.'), getpos('.'), #{ type: "\<C-v>" }))
+  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", "\<c-v>"))
+  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: "\<c-v>" }))
+
+  " 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: "\<c-v>" }))
 
   " Multiline with line visual mode
   call cursor(1, 1)
   call feedkeys("\<ESC>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("\<ESC>\<C-v>jj", 'tx')
-  call assert_equal(['o', 't', 't'], getregion('v', '.', "\<C-v>"))
+  call assert_equal(['o', 't', 't'],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
 
   call cursor(1, 1)
   call feedkeys("\<ESC>\<C-v>jj$", 'tx')
-  call assert_equal(['one', 'two', 'three'], getregion('v', '.', "\<C-v>"))
+  call assert_equal(['one', 'two', 'three'],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
 
   " 'virtualedit'
   set virtualedit=all
   call cursor(1, 1)
   call feedkeys("\<ESC>\<C-v>10ljj$", 'tx')
   call assert_equal(['one   ', 'two   ', 'three '],
-        \ getregion('v', '.', "\<C-v>"))
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   set virtualedit&
 
   " Invalid position
   call cursor(1, 1)
   call feedkeys("\<ESC>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("\<ESC>", 'tx')
-  call assert_equal([], getregion('v', '.', 'v'))
-
-  " using an unset mark
-  call assert_equal([], "'z"->getregion(".", 'V'))
+  call assert_fails("call getregion(1, 2)", 'E1211:')
+  call assert_fails("call getregion(getpos('.'), {})", 'E1211:')
+  call assert_equal([], getregion(getpos('.'), getpos('.'), #{ type: '' }))
+
   " 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("\<Esc>\<C-v>ljj", 'xt')
   call assert_equal(['cd', "\u00ab ", '34'],
-        \ getregion('v', '.', "\<C-v>"))
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   call cursor(1, 4)
   call feedkeys("\<Esc>\<C-v>ljj", 'xt')
   call assert_equal(['de', "\U0001f1e7", '45'],
-        \ getregion('v', '.', "\<C-v>"))
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   call cursor(1, 5)
   call feedkeys("\<Esc>\<C-v>jj", 'xt')
-  call assert_equal(['e', ' ', '5'], getregion('v', '.', "\<C-v>"))
+  call assert_equal(['e', ' ', '5'],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   call cursor(1, 1)
   call feedkeys("\<Esc>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", "\<c-v>"))
-  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: "\<c-v>" }))
+  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: "\<c-v>", exclusive: 
v:false }))
+  call assert_equal(['abcdefghij'],
+        \ getregion(getpos("'a"), getpos("'b"), #{ type: "\<c-v>", 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  c", "x  z", '', ''])
   call cursor(1, 1)
   call feedkeys("\<Esc>v2l", 'xt')
-  call assert_equal(["a        "], getregion('v', '.', 'v'))
+  call assert_equal(["a        "],
+        \ getregion(getpos('v'), getpos('.'), #{ type: 'v' }))
   call cursor(1, 1)
   call feedkeys("\<Esc>v$G", 'xt')
-  call assert_equal(["a        c", "x  z", ''], getregion('v', '.', 'v'))
+  call assert_equal(["a        c", "x  z", ''],
+        \ getregion(getpos('v'), getpos('.'), #{ type: 'v' }))
   call cursor(1, 1)
   call feedkeys("\<Esc>v$j", 'xt')
-  call assert_equal(["a        c", "x  z"], getregion('v', '.', 'v'))
+  call assert_equal(["a        c", "x  z"],
+        \ getregion(getpos('v'), getpos('.'), #{ type: 'v' }))
   call cursor(1, 1)
   call feedkeys("\<Esc>\<C-v>$j", 'xt')
-  call assert_equal(["a        c", "x  z"], getregion('v', '.', "\<C-v>"))
+  call assert_equal(["a        c", "x  z"],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   call cursor(1, 1)
   call feedkeys("\<Esc>\<C-v>$G", 'xt')
-  call assert_equal(["a", "x", '', ''], getregion('v', '.', "\<C-v>"))
+  call assert_equal(["a", "x", '', ''],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   call cursor(1, 1)
   call feedkeys("\<Esc>wv2j", 'xt')
-  call assert_equal(["c", "x   z"], getregion('v', '.', 'v'))
+  call assert_equal(["c", "x   z"],
+        \ getregion(getpos('v'), getpos('.'), #{ type: 'v' }))
+  set selection&
+
+  " Exclusive selection 2
+  new
+  call setline(1, ["a  c", "x  z", '', ''])
+  call cursor(1, 1)
+  call feedkeys("\<Esc>v2l", 'xt')
+  call assert_equal(["a        "],
+        \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
+  call cursor(1, 1)
+  call feedkeys("\<Esc>v$G", 'xt')
+  call assert_equal(["a        c", "x  z", ''],
+        \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
+  call cursor(1, 1)
+  call feedkeys("\<Esc>v$j", 'xt')
+  call assert_equal(["a        c", "x  z"],
+        \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
+  call cursor(1, 1)
+  call feedkeys("\<Esc>\<C-v>$j", 'xt')
+  call assert_equal(["a        c", "x  z"],
+        \ getregion(getpos('v'), getpos('.'),
+        \           #{ exclusive: v:true, type: "\<C-v>" }))
+  call cursor(1, 1)
+  call feedkeys("\<Esc>\<C-v>$G", 'xt')
+  call assert_equal(["a", "x", '', ''],
+        \ getregion(getpos('v'), getpos('.'),
+        \           #{ exclusive: v:true, type: "\<C-v>" }))
+  call cursor(1, 1)
+  call feedkeys("\<Esc>wv2j", 'xt')
+  call assert_equal(["c", "x   z"],
+        \ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
 
   " virtualedit
+  set selection=exclusive
   set virtualedit=all
   call cursor(1, 1)
   call feedkeys("\<Esc>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("\<Esc>2l\<C-v>2l2j", 'xt')
-  call assert_equal(['  ', '  ', '  '], getregion('v', '.', "\<C-v>"))
+  call assert_equal(['  ', '  ', '  '],
+        \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
   set virtualedit&
   set selection&
 
diff --git a/src/version.c b/src/version.c
index 5a6f4c13c..c6c536ab1 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    142,
 /**/
     141,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rfRy7-007RYA-A8%40256bit.org.

Raspunde prin e-mail lui