0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

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 <zeertzjq@outlook.com>
Signed-off-by: Shougo Matsushita <Shougo.Matsu@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Shougo Matsushita
2024-02-28 22:48:12 +01:00
committed by Christian Brabandt
parent d0d4adb609
commit 19b718828d
5 changed files with 212 additions and 102 deletions

View File

@@ -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 VIM REFERENCE MANUAL by Bram Moolenaar
@@ -263,7 +263,7 @@ getqflist({what}) Dict get specific quickfix list properties
getreg([{regname} [, 1 [, {list}]]]) getreg([{regname} [, 1 [, {list}]]])
String or List contents of a register String or List contents of a register
getreginfo([{regname}]) Dict information about 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} List get the text from {pos1} to {pos2}
getregtype([{regname}]) String type of a register getregtype([{regname}]) String type of a register
getscriptinfo([{opts}]) List list of sourced scripts getscriptinfo([{opts}]) List list of sourced scripts
@@ -4271,14 +4271,25 @@ getreginfo([{regname}]) *getreginfo()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetRegname()->getreginfo() GetRegname()->getreginfo()
getregion({pos1}, {pos2}, {type}) *getregion()* getregion({pos1}, {pos2} [, {opts}]) *getregion()*
Returns the list of strings from {pos1} to {pos2} as if it's Returns the list of strings from {pos1} to {pos2} in current
selected in visual mode of {type}. buffer.
For possible values of {pos1} and {pos2} see |line()|.
{type} is the selection type: {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 |characterwise| mode
"V" for |linewise| mode "V" for |linewise| mode
"<CTRL-V>" for |blockwise-visual| 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()|. You can get the last selection type by |visualmode()|.
If Visual mode is active, use |mode()| to get the Visual mode If Visual mode is active, use |mode()| to get the Visual mode
(e.g., in a |:vmap|). (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 - If the selection starts or ends in the middle of a multibyte
character, it is not included but its selected part is character, it is not included but its selected part is
substituted with spaces. substituted with spaces.
- If {pos1} or {pos2} equals "v" (see |line()|) and it is not in - If {pos1} or {pos2} is not current in the buffer, an empty
|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
list is returned. list is returned.
Examples: > Examples: >
:xnoremap <CR> :xnoremap <CR>
\ <Cmd>echow getregion('v', '.', mode())<CR> \ <Cmd>echow getregion(
\ getpos('v'), getpos('.'), #{ type: mode() })<CR>
< <
Can also be used as a |method|: > Can also be used as a |method|: >
'.'->getregion("'a", 'v') getpos('.')->getregion(getpos("'a"))
< <
getregtype([{regname}]) *getregtype()* getregtype([{regname}]) *getregtype()*
The result is a String, which is type of register {regname}. The result is a String, which is type of register {regname}.

View File

@@ -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_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_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_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_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[] = {arg_number, arg_number, arg_number};
static argcheck_T arg3_number_any_dict[] = {arg_number, arg_any, arg_dict_any}; 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}, ret_getreg, f_getreg},
{"getreginfo", 0, 1, FEARG_1, arg1_string, {"getreginfo", 0, 1, FEARG_1, arg1_string,
ret_dict_any, f_getreginfo}, 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}, ret_list_string, f_getregion},
{"getregtype", 0, 1, FEARG_1, arg1_string, {"getregtype", 0, 1, FEARG_1, arg1_string,
ret_string, f_getregtype}, ret_string, f_getregtype},
@@ -5491,41 +5492,43 @@ f_getregion(typval_T *argvars, typval_T *rettv)
int inclusive = TRUE; int inclusive = TRUE;
int fnum = -1; int fnum = -1;
pos_T p1, p2; pos_T p1, p2;
pos_T *fp = NULL; char_u *type;
char_u *pos1, *pos2, *type; char_u default_type[] = "v";
int save_virtual = -1; int save_virtual = -1;
int l; int l;
int region_type = -1; int region_type = -1;
int is_visual; int is_select_exclusive;
if (rettv_list_alloc(rettv) == FAIL) if (rettv_list_alloc(rettv) == FAIL)
return; return;
if (check_for_string_arg(argvars, 0) == FAIL if (check_for_list_arg(argvars, 0) == FAIL
|| check_for_string_arg(argvars, 1) == FAIL || check_for_list_arg(argvars, 1) == FAIL
|| check_for_string_arg(argvars, 2) == FAIL) || check_for_opt_dict_arg(argvars, 2) == FAIL)
return; return;
// NOTE: var2fpos() returns static pointer. if (list2fpos(&argvars[0], &p1, &fnum, NULL, FALSE) != OK
fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE); || (fnum >= 0 && fnum != curbuf->b_fnum))
if (fp == NULL || (fnum >= 0 && fnum != curbuf->b_fnum))
return; return;
p1 = *fp;
fp = var2fpos(&argvars[1], TRUE, &fnum, FALSE); if (list2fpos(&argvars[1], &p2, &fnum, NULL, FALSE) != OK
if (fp == NULL || (fnum >= 0 && fnum != curbuf->b_fnum)) || (fnum >= 0 && fnum != curbuf->b_fnum))
return; return;
p2 = *fp;
pos1 = tv_get_string(&argvars[0]); if (argvars[2].v_type == VAR_DICT)
pos2 = tv_get_string(&argvars[1]); {
type = tv_get_string(&argvars[2]); is_select_exclusive = dict_get_bool(
argvars[2].vval.v_dict, "exclusive", *p_sel == 'e');
is_visual = (pos1[0] == 'v' && pos1[1] == NUL) type = dict_get_string(
|| (pos2[0] == 'v' && pos2[1] == NUL); argvars[2].vval.v_dict, "type", FALSE);
if (type == NULL)
if (is_visual && !VIsual_active) type = default_type;
return; }
else
{
is_select_exclusive = *p_sel == 'e';
type = default_type;
}
if (type[0] == 'v' && type[1] == NUL) if (type[0] == 'v' && type[1] == NUL)
region_type = MCHAR; region_type = MCHAR;
@@ -5539,6 +5542,10 @@ f_getregion(typval_T *argvars, typval_T *rettv)
save_virtual = virtual_op; save_virtual = virtual_op;
virtual_op = virtual_active(); virtual_op = virtual_active();
// NOTE: Adjust is needed.
p1.col--;
p2.col--;
if (!LT_POS(p1, p2)) if (!LT_POS(p1, p2))
{ {
// swap position // swap position
@@ -5552,7 +5559,7 @@ f_getregion(typval_T *argvars, typval_T *rettv)
if (region_type == MCHAR) if (region_type == MCHAR)
{ {
// handle 'selection' == "exclusive" // handle 'selection' == "exclusive"
if (*p_sel == 'e' && !EQUAL_POS(p1, p2)) if (is_select_exclusive && !EQUAL_POS(p1, p2))
{ {
if (p2.coladd > 0) if (p2.coladd > 0)
p2.coladd--; p2.coladd--;
@@ -5590,7 +5597,7 @@ f_getregion(typval_T *argvars, typval_T *rettv)
oa.start = p1; oa.start = p1;
oa.end = p2; oa.end = p2;
oa.start_vcol = MIN(sc1, sc2); 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; oa.end_vcol = sc2 - 1;
else else
oa.end_vcol = MAX(ec1, ec2); oa.end_vcol = MAX(ec1, ec2);

View File

@@ -5198,12 +5198,11 @@ def Test_passing_type_to_builtin()
enddef enddef
def Test_getregion() 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']) 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('.', '.', 'v')) assert_equal([''], getregion(getpos('.'), getpos('.')))
v9.CheckDefExecFailure(['getregion("a", ".", "v")'], 'E1209:') v9.CheckDefExecFailure(['getregion(getpos("a"), getpos("."))'], 'E1209:')
v9.CheckDefExecAndScriptFailure(['getregion("", ".", "v")'], 'E1209: Invalid value for a line number')
enddef enddef
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker

View File

@@ -1638,80 +1638,113 @@ func Test_visual_getregion()
" Visual mode " Visual mode
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>vjl", 'tx') call feedkeys("\<ESC>vjl", 'tx')
call assert_equal(['one', 'tw'], 'v'->getregion('.', 'v')) call assert_equal(['one', 'tw'],
call assert_equal(['one', 'tw'], '.'->getregion('v', 'v')) \ 'v'->getpos()->getregion(getpos('.')))
call assert_equal(['o'], 'v'->getregion('v', 'v')) call assert_equal(['one', 'tw'],
call assert_equal(['w'], '.'->getregion('.', 'v')) \ '.'->getpos()->getregion(getpos('v')))
call assert_equal(['one', 'two'], '.'->getregion('v', 'V')) call assert_equal(['o'],
call assert_equal(['on', 'tw'], '.'->getregion('v', "\<C-v>")) \ '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 " Line visual mode
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>Vl", 'tx') call feedkeys("\<ESC>Vl", 'tx')
call assert_equal(['one'], getregion('v', '.', 'V')) call assert_equal(['one'],
call assert_equal(['one'], getregion('.', 'v', 'V')) \ getregion(getpos('v'), getpos('.'), #{ type: 'V' }))
call assert_equal(['one'], getregion('v', 'v', 'V')) call assert_equal(['one'],
call assert_equal(['one'], getregion('.', '.', 'V')) \ getregion(getpos('.'), getpos('v'), #{ type: 'V' }))
call assert_equal(['on'], '.'->getregion('v', 'v')) call assert_equal(['one'],
call assert_equal(['on'], '.'->getregion('v', "\<C-v>")) \ 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 " Block visual mode
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>\<C-v>ll", 'tx') call feedkeys("\<ESC>\<C-v>ll", 'tx')
call assert_equal(['one'], getregion('v', '.', "\<C-v>")) call assert_equal(['one'],
call assert_equal(['one'], getregion('.', 'v', "\<C-v>")) \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
call assert_equal(['o'], getregion('v', 'v', "\<C-v>")) call assert_equal(['one'],
call assert_equal(['e'], getregion('.', '.', "\<C-v>")) \ getregion(getpos('.'), getpos('v'), #{ type: "\<C-v>" }))
call assert_equal(['one'], '.'->getregion('v', 'V')) call assert_equal(['o'],
call assert_equal(['one'], '.'->getregion('v', 'v')) \ 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 " Using Marks
call setpos("'a", [0, 2, 3, 0]) call setpos("'a", [0, 2, 3, 0])
call cursor(1, 1) call cursor(1, 1)
call assert_equal(['one', 'two'], "'a"->getregion('.', 'v')) call assert_equal(['one', 'two'],
call assert_equal(['one', 'two'], "."->getregion("'a", 'v')) \ "'a"->getpos()->getregion(getpos('.'), #{ type: 'v' }))
call assert_equal(['one', 'two'], "."->getregion("'a", 'V')) call assert_equal(['one', 'two'],
call assert_equal(['two'], "'a"->getregion("'a", 'V')) \ "."->getpos()->getregion(getpos("'a"), #{ type: 'v' }))
call assert_equal(['one', 'two'], "."->getregion("'a", "\<c-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 " Multiline with line visual mode
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>Vjj", 'tx') 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 " Multiline with block visual mode
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>\<C-v>jj", 'tx') 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 cursor(1, 1)
call feedkeys("\<ESC>\<C-v>jj$", 'tx') 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' " 'virtualedit'
set virtualedit=all set virtualedit=all
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>\<C-v>10ljj$", 'tx') call feedkeys("\<ESC>\<C-v>10ljj$", 'tx')
call assert_equal(['one ', 'two ', 'three '], call assert_equal(['one ', 'two ', 'three '],
\ getregion('v', '.', "\<C-v>")) \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
set virtualedit& set virtualedit&
" Invalid position " Invalid position
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<ESC>vjj$", 'tx') call feedkeys("\<ESC>vjj$", 'tx')
call assert_fails("call getregion(1, 2, 'v')", 'E1174:') call assert_fails("call getregion(1, 2)", 'E1211:')
call assert_fails("call getregion('.', {}, 'v')", 'E1174:') call assert_fails("call getregion(getpos('.'), {})", 'E1211:')
call assert_equal([], getregion('', '.', 'v')) call assert_equal([], getregion(getpos('.'), getpos('.'), #{ type: '' }))
call assert_equal([], getregion('.', '.', ''))
call feedkeys("\<ESC>", 'tx')
call assert_equal([], getregion('v', '.', 'v'))
" using an unset mark
call assert_equal([], "'z"->getregion(".", 'V'))
" using the wrong type " using the wrong type
call assert_fails(':echo "."->getregion([],"V")', 'E1174:') call assert_fails(':echo "."->getpos()->getregion("$", [])', 'E1211:')
call assert_fails(':echo "."->getregion("$", {})', 'E1174:')
call assert_fails(':echo [0, 1, 1, 0]->getregion("$", "v")', 'E1174:')
" using a mark in another buffer " using a mark in another buffer
new new
let newbuf = bufnr() let newbuf = bufnr()
@@ -1719,8 +1752,8 @@ func Test_visual_getregion()
normal! GmA normal! GmA
wincmd p wincmd p
call assert_equal([newbuf, 10, 1, 0], getpos("'A")) call assert_equal([newbuf, 10, 1, 0], getpos("'A"))
call assert_equal([], getregion(".", "'A", 'v')) call assert_equal([], getregion(getpos('.'), getpos("'A"), #{ type: 'v' }))
call assert_equal([], getregion("'A", ".", 'v')) call assert_equal([], getregion(getpos("'A"), getpos('.'), #{ type: 'v' }))
exe newbuf .. 'bwipe!' exe newbuf .. 'bwipe!'
bwipe! bwipe!
@@ -1734,26 +1767,47 @@ func Test_visual_getregion()
call cursor(1, 3) call cursor(1, 3)
call feedkeys("\<Esc>\<C-v>ljj", 'xt') call feedkeys("\<Esc>\<C-v>ljj", 'xt')
call assert_equal(['cd', "\u00ab ", '34'], call assert_equal(['cd', "\u00ab ", '34'],
\ getregion('v', '.', "\<C-v>")) \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
call cursor(1, 4) call cursor(1, 4)
call feedkeys("\<Esc>\<C-v>ljj", 'xt') call feedkeys("\<Esc>\<C-v>ljj", 'xt')
call assert_equal(['de', "\U0001f1e7", '45'], call assert_equal(['de', "\U0001f1e7", '45'],
\ getregion('v', '.', "\<C-v>")) \ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
call cursor(1, 5) call cursor(1, 5)
call feedkeys("\<Esc>\<C-v>jj", 'xt') 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 cursor(1, 1)
call feedkeys("\<Esc>vj", 'xt') 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 " marks on multibyte chars
set selection=exclusive set selection=exclusive
call setpos("'a", [0, 1, 11, 0]) call setpos("'a", [0, 1, 11, 0])
call setpos("'b", [0, 2, 16, 0]) call setpos("'b", [0, 2, 16, 0])
call setpos("'c", [0, 2, 0, 0]) call setpos("'c", [0, 2, 0, 0])
call cursor(1, 1) call cursor(1, 1)
call assert_equal(['ghijk', '🇨«🇩'], getregion("'a", "'b", "\<c-v>")) call assert_equal(['ghijk', '🇨«🇩'],
call assert_equal(['k«', '🇦«🇧«🇨'], getregion("'a", "'b", "v")) \ getregion(getpos("'a"), getpos("'b"), #{ type: "\<c-v>" }))
call assert_equal(['k«'], getregion("'a", "'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! bwipe!
@@ -1763,31 +1817,71 @@ func Test_visual_getregion()
call setline(1, ["a\tc", "x\tz", '', '']) call setline(1, ["a\tc", "x\tz", '', ''])
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<Esc>v2l", 'xt') call feedkeys("\<Esc>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 cursor(1, 1)
call feedkeys("\<Esc>v$G", 'xt') call feedkeys("\<Esc>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 cursor(1, 1)
call feedkeys("\<Esc>v$j", 'xt') call feedkeys("\<Esc>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 cursor(1, 1)
call feedkeys("\<Esc>\<C-v>$j", 'xt') call feedkeys("\<Esc>\<C-v>$j", 'xt')
call assert_equal(["a\tc", "x\tz"], getregion('v', '.', "\<C-v>")) call assert_equal(["a\tc", "x\tz"],
\ getregion(getpos('v'), getpos('.'), #{ type: "\<C-v>" }))
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<Esc>\<C-v>$G", 'xt') 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 cursor(1, 1)
call feedkeys("\<Esc>wv2j", 'xt') call feedkeys("\<Esc>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("\<Esc>v2l", 'xt')
call assert_equal(["a\t"],
\ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
call cursor(1, 1)
call feedkeys("\<Esc>v$G", 'xt')
call assert_equal(["a\tc", "x\tz", ''],
\ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
call cursor(1, 1)
call feedkeys("\<Esc>v$j", 'xt')
call assert_equal(["a\tc", "x\tz"],
\ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
call cursor(1, 1)
call feedkeys("\<Esc>\<C-v>$j", 'xt')
call assert_equal(["a\tc", "x\tz"],
\ 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\tz"],
\ getregion(getpos('v'), getpos('.'), #{ exclusive: v:true }))
" virtualedit " virtualedit
set selection=exclusive
set virtualedit=all set virtualedit=all
call cursor(1, 1) call cursor(1, 1)
call feedkeys("\<Esc>2lv2lj", 'xt') 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 cursor(1, 1)
call feedkeys("\<Esc>2l\<C-v>2l2j", 'xt') 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 virtualedit&
set selection& set selection&

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
142,
/**/ /**/
141, 141,
/**/ /**/