patch 9.1.0394: Cannot get a list of positions describing a region

Commit: 
https://github.com/vim/vim/commit/b4757e627e6c83d1c8e5535d4887a82d6a5efdd0
Author: Shougo Matsushita <shougo.ma...@gmail.com>
Date:   Tue May 7 20:49:24 2024 +0200

    patch 9.1.0394: Cannot get a list of positions describing a region
    
    Problem:  Cannot get a list of positions describing a region
              (Justin M. Keyes, after v9.1.0120)
    Solution: Add the getregionpos() function
              (Shougo Matsushita)
    
    fixes: #14609
    closes: #14617
    
    Co-authored-by: Justin M. Keyes <justi...@gmail.com>
    Signed-off-by: Shougo Matsushita <shougo.ma...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index f62cc83ca..b37170ce7 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 May 05
+*builtin.txt*  For Vim version 9.1.  Last change: 2024 May 07
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -265,6 +265,8 @@ getreg([{regname} [, 1 [, {list}]]])
 getreginfo([{regname}])                Dict    information about a register
 getregion({pos1}, {pos2} [, {opts}])
                                List    get the text from {pos1} to {pos2}
+getregionpos({pos1}, {pos2} [, {opts}])
+                               List    get a list of positions for a region
 getregtype([{regname}])                String  type of a register
 getscriptinfo([{opts}])                List    list of sourced scripts
 gettabinfo([{expr}])           List    list of tab pages
@@ -4327,6 +4329,26 @@ getregion({pos1}, {pos2} [, {opts}])                     
*getregion()*
                Can also be used as a |method|: >
                        getpos('.')->getregion(getpos("'a"))
 <
+getregionpos({pos1}, {pos2} [, {opts}])            *getregionpos()*
+               Same as |getregion()|, but returns a list of positions
+               describing the buffer text segments bound by {pos1} and
+               {pos2}.
+               The segments are a pair of positions for every line: >
+                       [[{start_pos}, {end_pos}], ...]
+<
+               The position is a |List| with four numbers:
+                   [bufnum, lnum, col, off]
+               "bufnum" is the buffer number.
+               "lnum" and "col" are the position in the buffer.  The first
+               column is 1.
+               The "off" number is zero, unless 'virtualedit' is used.  Then
+               it is the offset in screen columns from the start of the
+               character.  E.g., a position within a <Tab> or after the last
+               character.
+
+               Can also be used as a |method|: >
+                       getpos('.')->getregionpos(getpos("'a"))
+<
 getregtype([{regname}])                                        *getregtype()*
                The result is a String, which is type of register {regname}.
                The value will be one of:
diff --git a/runtime/doc/tags b/runtime/doc/tags
index e3562813b..0c9aef26c 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -7799,6 +7799,7 @@ getreg()  builtin.txt     /*getreg()*
 getreginfo()   builtin.txt     /*getreginfo()*
 getregion()    builtin.txt     /*getregion()*
 getregion-notes        builtin.txt     /*getregion-notes*
+getregionpos() builtin.txt     /*getregionpos()*
 getregtype()   builtin.txt     /*getregtype()*
 getscript      pi_getscript.txt        /*getscript*
 getscript-autoinstall  pi_getscript.txt        /*getscript-autoinstall*
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 6137cfd5a..26651ebb1 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -1,4 +1,4 @@
-*usr_41.txt*   For Vim version 9.1.  Last change: 2024 Apr 26
+*usr_41.txt*   For Vim version 9.1.  Last change: 2024 May 07
 
                     VIM USER MANUAL - by Bram Moolenaar
 
@@ -930,6 +930,7 @@ Cursor and mark position:           *cursor-functions* 
*mark-functions*
 Working with text in the current buffer:               *text-functions*
        getline()               get a line or list of lines from the buffer
        getregion()             get a region of text from the buffer
+       getregionpos()          get a list of positions for a region
        setline()               replace a line in the buffer
        append()                append line or list of lines in the buffer
        indent()                indent of a specific line
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 9259cde9e..192c3ee75 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -41574,6 +41574,7 @@ Functions: ~
 |matchbufline()|       all the matches of a pattern in a buffer
 |matchstrlist()|       all the matches of a pattern in a List of strings
 |getregion()|          get a region of text from a buffer
+|getregionpos()|       get a list of positions for a region
 
 
 Autocommands: ~
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 7c7a20243..cca7e2ca4 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -73,6 +73,7 @@ static void f_getpos(typval_T *argvars, typval_T *rettv);
 static void f_getreg(typval_T *argvars, typval_T *rettv);
 static void f_getreginfo(typval_T *argvars, typval_T *rettv);
 static void f_getregion(typval_T *argvars, typval_T *rettv);
+static void f_getregionpos(typval_T *argvars, typval_T *rettv);
 static void f_getregtype(typval_T *argvars, typval_T *rettv);
 static void f_gettagstack(typval_T *argvars, typval_T *rettv);
 static void f_gettext(typval_T *argvars, typval_T *rettv);
@@ -2136,6 +2137,8 @@ static funcentry_T global_functions[] =
                        ret_dict_any,       f_getreginfo},
     {"getregion",      2, 3, FEARG_1,      arg3_list_list_dict,
                        ret_list_string,    f_getregion},
+    {"getregionpos",   2, 3, FEARG_1,      arg3_list_list_dict,
+                       ret_list_string,    f_getregionpos},
     {"getregtype",     0, 1, FEARG_1,      arg1_string,
                        ret_string,         f_getregtype},
     {"getscriptinfo",  0, 1, 0,            arg1_dict_any,
@@ -5481,40 +5484,35 @@ block_def2str(struct block_def *bd)
     return ret;
 }
 
-/*
- * "getregion()" function
- */
-    static void
-f_getregion(typval_T *argvars, typval_T *rettv)
-{
-    linenr_T           lnum;
-    oparg_T            oa;
-    struct block_def   bd;
-    char_u             *akt = NULL;
-    int                        inclusive = TRUE;
-    int                        fnum1 = -1, fnum2 = -1;
-    pos_T              p1, p2;
-    char_u             *type;
-    buf_T              *save_curbuf;
-    buf_T              *findbuf;
-    char_u             default_type[] = "v";
-    int                        save_virtual;
-    int                        l;
-    int                        region_type = -1;
-    int                        is_select_exclusive;
+    static int
+getregionpos(
+    typval_T   *argvars,
+    typval_T   *rettv,
+    pos_T      *p1, pos_T *p2,
+    int                *inclusive,
+    int                *region_type,
+    oparg_T    *oa,
+    int                *fnum)
+{
+    int                fnum1 = -1, fnum2 = -1;
+    char_u     *type;
+    buf_T      *findbuf;
+    char_u     default_type[] = "v";
+    int                is_select_exclusive;
+    int                l;
 
     if (rettv_list_alloc(rettv) == FAIL)
-       return;
+       return 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;
+       return FAIL;
 
-    if (list2fpos(&argvars[0], &p1, &fnum1, NULL, FALSE) != OK
-           || list2fpos(&argvars[1], &p2, &fnum2, NULL, FALSE) != OK
+    if (list2fpos(&argvars[0], p1, &fnum1, NULL, FALSE) != OK
+           || list2fpos(&argvars[1], p2, &fnum2, NULL, FALSE) != OK
            || fnum1 != fnum2)
-       return;
+       return FAIL;
 
     if (argvars[2].v_type == VAR_DICT)
     {
@@ -5532,125 +5530,152 @@ f_getregion(typval_T *argvars, typval_T *rettv)
     }
 
     if (type[0] == 'v' && type[1] == NUL)
-       region_type = MCHAR;
+       *region_type = MCHAR;
     else if (type[0] == 'V' && type[1] == NUL)
-       region_type = MLINE;
+       *region_type = MLINE;
     else if (type[0] == Ctrl_V && type[1] == NUL)
-       region_type = MBLOCK;
+       *region_type = MBLOCK;
     else
     {
        semsg(_(e_invalid_value_for_argument_str_str), "type", type);
-       return;
+       return FAIL;
     }
 
     findbuf = fnum1 != 0 ? buflist_findnr(fnum1) : curbuf;
+    *fnum = fnum1 != 0 ? fnum1 : curbuf->b_fnum;
     if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL)
     {
        emsg(_(e_buffer_is_not_loaded));
-       return;
+       return FAIL;
     }
 
-    if (p1.lnum < 1 || p1.lnum > findbuf->b_ml.ml_line_count)
+    if (p1->lnum < 1 || p1->lnum > findbuf->b_ml.ml_line_count)
     {
-       semsg(_(e_invalid_line_number_nr), p1.lnum);
-       return;
+       semsg(_(e_invalid_line_number_nr), p1->lnum);
+       return FAIL;
     }
-    if (p1.col == MAXCOL)
-       p1.col = ml_get_buf_len(findbuf, p1.lnum) + 1;
-    else if (p1.col < 1 || p1.col > ml_get_buf_len(findbuf, p1.lnum) + 1)
+    if (p1->col == MAXCOL)
+       p1->col = ml_get_buf_len(findbuf, p1->lnum) + 1;
+    else if (p1->col < 1 || p1->col > ml_get_buf_len(findbuf, p1->lnum) + 1)
     {
-       semsg(_(e_invalid_column_number_nr), p1.col);
-       return;
+       semsg(_(e_invalid_column_number_nr), p1->col);
+       return FAIL;
     }
 
-    if (p2.lnum < 1 || p2.lnum > findbuf->b_ml.ml_line_count)
+    if (p2->lnum < 1 || p2->lnum > findbuf->b_ml.ml_line_count)
     {
-       semsg(_(e_invalid_line_number_nr), p2.lnum);
-       return;
+       semsg(_(e_invalid_line_number_nr), p2->lnum);
+       return FAIL;
     }
-    if (p2.col == MAXCOL)
-       p2.col = ml_get_buf_len(findbuf, p2.lnum) + 1;
-    else if (p2.col < 1 || p2.col > ml_get_buf_len(findbuf, p2.lnum) + 1)
+    if (p2->col == MAXCOL)
+       p2->col = ml_get_buf_len(findbuf, p2->lnum) + 1;
+    else if (p2->col < 1 || p2->col > ml_get_buf_len(findbuf, p2->lnum) + 1)
     {
-       semsg(_(e_invalid_column_number_nr), p2.col);
-       return;
+       semsg(_(e_invalid_column_number_nr), p2->col);
+       return FAIL;
     }
 
-    save_curbuf = curbuf;
     curbuf = findbuf;
     curwin->w_buffer = curbuf;
-    save_virtual = virtual_op;
     virtual_op = virtual_active();
 
-    // NOTE: Adjust is needed.
-    p1.col--;
-    p2.col--;
+    // NOTE: Adjustment is needed.
+    p1->col--;
+    p2->col--;
 
-    if (!LT_POS(p1, p2))
+    if (!LT_POS(*p1, *p2))
     {
        // swap position
        pos_T p;
 
-       p = p1;
-       p1 = p2;
-       p2 = p;
+       p = *p1;
+       *p1 = *p2;
+       *p2 = p;
     }
 
-    if (region_type == MCHAR)
+    if (*region_type == MCHAR)
     {
        // handle 'selection' == "exclusive"
-       if (is_select_exclusive && !EQUAL_POS(p1, p2))
+       if (is_select_exclusive && !EQUAL_POS(*p1, *p2))
        {
-           if (p2.coladd > 0)
-               p2.coladd--;
-           else if (p2.col > 0)
+           if (p2->coladd > 0)
+               p2->coladd--;
+           else if (p2->col > 0)
            {
-               p2.col--;
+               p2->col--;
 
-               mb_adjustpos(curbuf, &p2);
+               mb_adjustpos(curbuf, p2);
            }
-           else if (p2.lnum > 1)
+           else if (p2->lnum > 1)
            {
-               p2.lnum--;
-               p2.col = ml_get_len(p2.lnum);
-               if (p2.col > 0)
+               p2->lnum--;
+               p2->col = ml_get_len(p2->lnum);
+               if (p2->col > 0)
                {
-                   p2.col--;
+                   p2->col--;
 
-                   mb_adjustpos(curbuf, &p2);
+                   mb_adjustpos(curbuf, p2);
                }
            }
        }
        // if fp2 is on NUL (empty line) inclusive becomes false
-       if (*ml_get_pos(&p2) == NUL && !virtual_op)
-           inclusive = FALSE;
+       if (*ml_get_pos(p2) == NUL && !virtual_op)
+           *inclusive = FALSE;
     }
-    else if (region_type == MBLOCK)
+    else if (*region_type == MBLOCK)
     {
        colnr_T sc1, ec1, sc2, ec2;
 
-       getvvcol(curwin, &p1, &sc1, NULL, &ec1);
-       getvvcol(curwin, &p2, &sc2, NULL, &ec2);
-       oa.motion_type = MBLOCK;
-       oa.inclusive = TRUE;
-       oa.op_type = OP_NOP;
-       oa.start = p1;
-       oa.end = p2;
-       oa.start_vcol = MIN(sc1, sc2);
+       getvvcol(curwin, p1, &sc1, NULL, &ec1);
+       getvvcol(curwin, p2, &sc2, NULL, &ec2);
+       oa->motion_type = MBLOCK;
+       oa->inclusive = TRUE;
+       oa->op_type = OP_NOP;
+       oa->start = *p1;
+       oa->end = *p2;
+       oa->start_vcol = MIN(sc1, sc2);
        if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1)
-           oa.end_vcol = sc2 - 1;
+           oa->end_vcol = sc2 - 1;
        else
-           oa.end_vcol = MAX(ec1, ec2);
+           oa->end_vcol = MAX(ec1, ec2);
     }
 
     // Include the trailing byte of a multi-byte char.
-    l = utfc_ptr2len((char_u *)ml_get_pos(&p2));
+    l = mb_ptr2len((char_u *)ml_get_pos(p2));
     if (l > 1)
-       p2.col += l - 1;
+       p2->col += l - 1;
+
+    return OK;
+}
+
+/*
+ * "getregion()" function
+ */
+    static void
+f_getregion(typval_T *argvars, typval_T *rettv)
+{
+    pos_T              p1, p2;
+    int                        inclusive = TRUE;
+    int                        region_type = -1;
+    oparg_T            oa;
+    int                        fnum;
+
+    buf_T              *save_curbuf;
+    int                        save_virtual;
+    char_u             *akt = NULL;
+    linenr_T           lnum;
+
+    save_curbuf = curbuf;
+    save_virtual = virtual_op;
+
+    if (getregionpos(argvars, rettv,
+               &p1, &p2, &inclusive, &region_type, &oa, &fnum) == FAIL)
+       return;
 
     for (lnum = p1.lnum; lnum <= p2.lnum; lnum++)
     {
        int ret = 0;
+       struct block_def        bd;
 
        if (region_type == MLINE)
            akt = vim_strsave(ml_get(lnum));
@@ -5681,6 +5706,127 @@ f_getregion(typval_T *argvars, typval_T *rettv)
        }
     }
 
+    // getregionpos() breaks curbuf and virtual_op
+    curbuf = save_curbuf;
+    curwin->w_buffer = curbuf;
+    virtual_op = save_virtual;
+}
+
+    static void
+add_regionpos_range(
+    typval_T   *rettv,
+    int                bufnr,
+    int                lnum1,
+    int                col1,
+    int                coladd1,
+    int                lnum2,
+    int                col2,
+    int                coladd2)
+{
+    list_T     *l1, *l2, *l3;
+    buf_T      *findbuf;
+    int                max_col1, max_col2;
+
+    l1 = list_alloc();
+    if (l1 == NULL)
+       return;
+
+    if (list_append_list(rettv->vval.v_list, l1) == FAIL)
+    {
+       vim_free(l1);
+       return;
+    }
+
+    l2 = list_alloc();
+    if (l2 == NULL)
+       return;
+
+    if (list_append_list(l1, l2) == FAIL)
+    {
+       vim_free(l2);
+       return;
+    }
+
+    l3 = list_alloc();
+    if (l3 == NULL)
+       return;
+
+    if (list_append_list(l1, l3) == FAIL)
+    {
+       vim_free(l3);
+       return;
+    }
+
+    findbuf = bufnr != 0 ? buflist_findnr(bufnr) : curbuf;
+
+    max_col1 = ml_get_buf_len(findbuf, lnum1);
+    list_append_number(l2, bufnr);
+    list_append_number(l2, lnum1);
+    list_append_number(l2, col1 > max_col1 ? max_col1 : col1);
+    list_append_number(l2, coladd1);
+
+    max_col2 = ml_get_buf_len(findbuf, lnum2);
+    list_append_number(l3, bufnr);
+    list_append_number(l3, lnum2);
+    list_append_number(l3, col2 > max_col2 ? max_col2 : col2);
+    list_append_number(l3, coladd2);
+}
+
+/*
+ * "getregionpos()" function
+ */
+    static void
+f_getregionpos(typval_T *argvars, typval_T *rettv)
+{
+    pos_T      p1, p2;
+    int                inclusive = TRUE;
+    int                region_type = -1;
+    oparg_T    oa;
+    int                fnum;
+    int                lnum;
+
+    buf_T      *save_curbuf;
+    int                save_virtual;
+
+    save_curbuf = curbuf;
+    save_virtual = virtual_op;
+
+    if (getregionpos(argvars, rettv,
+               &p1, &p2, &inclusive, &region_type, &oa, &fnum) == FAIL)
+       return;
+
+    for (lnum = p1.lnum; lnum <= p2.lnum; lnum++)
+    {
+       struct block_def        bd;
+       int                     start_col, end_col;
+
+       if (region_type == MLINE)
+       {
+           start_col = 1;
+           end_col = MAXCOL;
+       }
+       else if (region_type == MBLOCK)
+       {
+           block_prep(&oa, &bd, lnum, FALSE);
+           start_col = bd.start_vcol + 1;
+           end_col = bd.end_vcol;
+       }
+       else if (p1.lnum < lnum && lnum < p2.lnum)
+       {
+           start_col = 1;
+           end_col = MAXCOL;
+       }
+       else
+       {
+           start_col = p1.lnum == lnum ? p1.col + 1 : 1;
+           end_col = p2.lnum == lnum ? p2.col + 1 : MAXCOL;
+       }
+
+       add_regionpos_range(rettv, fnum, lnum, start_col,
+               p1.coladd, lnum, end_col, p2.coladd);
+    }
+
+    // getregionpos() may change curbuf and virtual_op
     curbuf = save_curbuf;
     curwin->w_buffer = curbuf;
     virtual_op = save_virtual;
diff --git a/src/testdir/test_vim9_builtin.vim 
b/src/testdir/test_vim9_builtin.vim
index 83153ad08..7a830189c 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -5181,10 +5181,26 @@ enddef
 
 def Test_getregion()
   assert_equal(['x'], getregion(getpos('.'), getpos('.'))->map((_, _) => 'x'))
-
-  v9.CheckSourceDefAndScriptFailure(['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('.')))
+  assert_equal(['x'], getregionpos(getpos('.'), getpos('.'))->map((_, _) => 
'x'))
+
+  v9.CheckSourceDefAndScriptFailure(
+      ['getregion(10, getpos("."))'],
+      ['E1013: Argument 1: type mismatch, expected list<any> but got number', 
'E1211: List required for argument 1']
+  )
+  v9.CheckSourceDefAndScriptFailure(
+      ['getregionpos(10, getpos("."))'],
+      ['E1013: Argument 1: type mismatch, expected list<any> but got number', 
'E1211: List required for argument 1']
+  )
+  assert_equal(
+      [''],
+      getregion(getpos('.'), getpos('.'))
+  )
+  assert_equal(
+      [[[bufnr('%'), 1, 0, 0], [bufnr('%'), 1, 0, 0]]],
+      getregionpos(getpos('.'), getpos('.'))
+  )
   v9.CheckSourceDefExecFailure(['getregion(getpos("a"), getpos("."))'], 
'E1209:')
+  v9.CheckSourceDefExecFailure(['getregionpos(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 dff615013..9b8eed40e 100644
--- a/src/testdir/test_visual.vim
+++ b/src/testdir/test_visual.vim
@@ -1642,16 +1642,44 @@ func Test_visual_getregion()
     call feedkeys("\<ESC>vjl", 'tx')
     call assert_equal(['one', 'tw'],
           \ 'v'->getpos()->getregion(getpos('.')))
+    call assert_equal([
+          \   [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
+          \   [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]]
+          \ ],
+          \ 'v'->getpos()->getregionpos(getpos('.')))
     call assert_equal(['one', 'tw'],
           \ '.'->getpos()->getregion(getpos('v')))
+    call assert_equal([
+          \   [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
+          \   [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]]
+          \ ],
+          \ '.'->getpos()->getregionpos(getpos('v')))
     call assert_equal(['o'],
           \ 'v'->getpos()->getregion(getpos('v')))
+    call assert_equal([
+          \   [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 1, 0]],
+          \ ],
+          \ 'v'->getpos()->getregionpos(getpos('v')))
     call assert_equal(['w'],
           \ '.'->getpos()->getregion(getpos('.'), {'type': 'v' }))
+    call assert_equal([
+          \   [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 2, 0]],
+          \ ],
+          \ '.'->getpos()->getregionpos(getpos('.'), {'type': 'v' }))
     call assert_equal(['one', 'two'],
           \ getpos('.')->getregion(getpos('v'), {'type': 'V' }))
+    call assert_equal([
+          \   [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 3, 0]],
+          \   [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 3, 0]],
+          \ ],
+          \ getpos('.')->getregionpos(getpos('v'), {'type': 'V' }))
     call assert_equal(['on', 'tw'],
           \ getpos('.')->getregion(getpos('v'), {'type': "\<C-v>" }))
+    call assert_equal([
+          \   [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 2, 0]],
+          \   [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 2, 0]],
+          \ ],
+          \ getpos('.')->getregionpos(getpos('v'), {'type': "\<C-v>" }))
 
     #" Line visual mode
     call cursor(1, 1)
@@ -1746,9 +1774,13 @@ func Test_visual_getregion()
     call assert_fails("call getregion(1, 2)", 'E1211:')
     call assert_fails("call getregion(getpos('.'), {})", 'E1211:')
     call assert_fails(':echo "."->getpos()->getregion("$", [])', 'E1211:')
+    call assert_fails("call getregionpos(1, 2)", 'E1211:')
+    call assert_fails("call getregionpos(getpos('.'), {})", 'E1211:')
+    call assert_fails(':echo "."->getpos()->getregionpos("$", [])', 'E1211:')
 
     #" using invalid value for "type"
     call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '' 
})", 'E475:')
+    call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '' 
})", 'E475:')
 
     #" using a mark from another buffer to current buffer
     new
@@ -1759,13 +1791,20 @@ func Test_visual_getregion()
     call assert_equal([g:buf, 10, 1, 0], getpos("'A"))
     call assert_equal([], getregion(getpos('.'), getpos("'A"), {'type': 'v' }))
     call assert_equal([], getregion(getpos("'A"), getpos('.'), {'type': 'v' }))
+    call assert_equal([], getregionpos(getpos('.'), getpos("'A"), {'type': 'v' 
}))
+    call assert_equal([], getregionpos(getpos("'A"), getpos('.'), {'type': 'v' 
}))
 
     #" using two marks from another buffer
     wincmd p
     normal! GmB
     wincmd p
     call assert_equal([g:buf, 10, 1, 0], getpos("'B"))
-    call assert_equal(['9'], getregion(getpos("'B"), getpos("'A"), {'type': 
'v' }))
+    call assert_equal(['9'],
+          \ getregion(getpos("'B"), getpos("'A"), {'type': 'v' }))
+    call assert_equal([
+          \   [[g:buf, 10, 1, 0], [g:buf, 10, 1, 0]],
+          \ ],
+          \ getregionpos(getpos("'B"), getpos("'A"), {'type': 'v' }))
 
     #" using two positions from another buffer
     for type in ['v', 'V', "\<C-V>"]
@@ -1788,6 +1827,8 @@ func Test_visual_getregion()
     call assert_fails('call getregion([g:buf, 10, 0, 0], [g:buf, 1, 1, 0])', 
'E964:')
     call assert_fails('call getregion([g:buf, 1, 1, 0], [g:buf, 10, 3, 0])', 
'E964:')
     call assert_fails('call getregion([g:buf, 10, 3, 0], [g:buf, 1, 1, 0])', 
'E964:')
+    call assert_fails('call getregion([g:buf, 1, 0, 0], [g:buf, 1, 1, 0])', 
'E964:')
+    call assert_fails('call getregion([g:buf, 1, 1, 0], [g:buf, 1, 0, 0])', 
'E964:')
 
     #" using invalid buffer
     call assert_fails('call getregion([10000, 10, 1, 0], [10000, 10, 1, 0])', 
'E681:')
@@ -1819,6 +1860,12 @@ func Test_visual_getregion()
     call feedkeys("\<Esc>\<C-v>jj", 'xt')
     call assert_equal(['e', ' ', '5'],
           \ getregion(getpos('v'), getpos('.'), {'type': "\<C-v>" }))
+    call assert_equal([
+          \   [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 13, 0]],
+          \   [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 22, 0]],
+          \   [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 5, 0]],
+          \ ],
+          \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' }))
     call cursor(1, 1)
     call feedkeys("\<Esc>vj", 'xt')
     call assert_equal(['abcdefghijk«', "\U0001f1e6"],
@@ -1831,7 +1878,7 @@ func Test_visual_getregion()
     call setpos("'c", [0, 2, 0, 0])
     call cursor(1, 1)
     call assert_equal(['ghijk', '🇨«🇩'],
-          \ getregion(getpos("'a"), getpos("'b"), {'type': "\<c-v>" }))
+          \ getregion(getpos("'a"), getpos("'b"), {'type': "\<C-v>" }))
     call assert_equal(['k«', '🇦«🇧«🇨'],
           \ getregion(getpos("'a"), getpos("'b"), {'type': 'v' }))
     call assert_equal(['k«'],
@@ -1958,4 +2005,30 @@ func Test_getregion_invalid_buf()
   bwipe!
 endfunc
 
+func Test_getregion_maxcol()
+  new
+  autocmd TextYankPost *
+        \ : if v:event.operator ==? 'y'
+        \ | call assert_equal([
+        \                       [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
+        \                     ],
+        \                     getregionpos(getpos("'["), getpos("']"),
+        \                                  #{ mode: visualmode() }))
+        \ | call assert_equal(['abcd'],
+        \                     getregion(getpos("'["), getpos("']"),
+        \                               #{ mode: visualmode() }))
+        \ | call assert_equal([
+        \                       [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]],
+        \                     ],
+        \                     getregionpos(getpos("']"), getpos("'["),
+        \                                  #{ mode: visualmode() }))
+        \ | call assert_equal(['abcd'],
+        \                     getregion(getpos("']"), getpos("'["),
+        \                               #{ mode: visualmode() }))
+        \ | endif
+  call setline(1, ['abcd', 'efghij'])
+  normal yy
+  bwipe!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 5312bfef4..128197063 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 */
+/**/
+    394,
 /**/
     393,
 /**/

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1s4Q2m-004St5-Gw%40256bit.org.

Raspunde prin e-mail lui