forked from aniani/vim
patch 8.2.2449: Vim9: flatten() always changes the list type
Problem: Vim9: flatten() always changes the list type. Solution: Disallow using flatten() and add flattennew().
This commit is contained in:
parent
9d20daffc2
commit
3b69006973
@ -2549,6 +2549,8 @@ finddir({name} [, {path} [, {count}]])
|
||||
findfile({name} [, {path} [, {count}]])
|
||||
String find file {name} in {path}
|
||||
flatten({list} [, {maxdepth}]) List flatten {list} up to {maxdepth} levels
|
||||
flattennew({list} [, {maxdepth}])
|
||||
List flatten a copy of {list}
|
||||
float2nr({expr}) Number convert Float {expr} to a Number
|
||||
floor({expr}) Float round {expr} down
|
||||
fmod({expr1}, {expr2}) Float remainder of {expr1} / {expr2}
|
||||
@ -4712,8 +4714,10 @@ flatten({list} [, {maxdepth}]) *flatten()*
|
||||
Flatten {list} up to {maxdepth} levels. Without {maxdepth}
|
||||
the result is a |List| without nesting, as if {maxdepth} is
|
||||
a very large number.
|
||||
The {list} is changed in place, make a copy first if you do
|
||||
The {list} is changed in place, use |flattennew()| if you do
|
||||
not want that.
|
||||
In Vim9 script flatten() cannot be used, you must always use
|
||||
|flattennew()|.
|
||||
*E900*
|
||||
{maxdepth} means how deep in nested lists changes are made.
|
||||
{list} is not modified when {maxdepth} is 0.
|
||||
@ -4727,6 +4731,10 @@ flatten({list} [, {maxdepth}]) *flatten()*
|
||||
:echo flatten([1, [2, [3, 4]], 5], 1)
|
||||
< [1, 2, [3, 4], 5]
|
||||
|
||||
flattennew({list} [, {maxdepth}]) *flattennew()*
|
||||
Like |flatten()| but first make a copy of {list}.
|
||||
|
||||
|
||||
float2nr({expr}) *float2nr()*
|
||||
Convert {expr} to a Number by omitting the part after the
|
||||
decimal point.
|
||||
|
@ -665,6 +665,7 @@ List manipulation: *list-functions*
|
||||
count() count number of times a value appears in a List
|
||||
repeat() repeat a List multiple times
|
||||
flatten() flatten a List
|
||||
flattennew() flatten a copy of a List
|
||||
|
||||
Dictionary manipulation: *dict-functions*
|
||||
get() get an entry without an error for a wrong key
|
||||
|
@ -351,3 +351,5 @@ EXTERN char e_cannot_change_arglist_recursively[]
|
||||
INIT(= N_("E1156: Cannot change the argument list recursively"));
|
||||
EXTERN char e_missing_return_type[]
|
||||
INIT(= N_("E1157: Missing return type"));
|
||||
EXTERN char e_cannot_use_flatten_in_vim9_script[]
|
||||
INIT(= N_("E1158: Cannot use flatten() in Vim9 script"));
|
||||
|
@ -954,6 +954,8 @@ static funcentry_T global_functions[] =
|
||||
ret_string, f_findfile},
|
||||
{"flatten", 1, 2, FEARG_1, NULL,
|
||||
ret_list_any, f_flatten},
|
||||
{"flattennew", 1, 2, FEARG_1, NULL,
|
||||
ret_list_any, f_flattennew},
|
||||
{"float2nr", 1, 1, FEARG_1, NULL,
|
||||
ret_number, FLOAT_FUNC(f_float2nr)},
|
||||
{"floor", 1, 1, FEARG_1, NULL,
|
||||
|
62
src/list.c
62
src/list.c
@ -740,7 +740,7 @@ list_insert(list_T *l, listitem_T *ni, listitem_T *item)
|
||||
* It does nothing if "maxdepth" is 0.
|
||||
* Returns FAIL when out of memory.
|
||||
*/
|
||||
static int
|
||||
static void
|
||||
list_flatten(list_T *list, long maxdepth)
|
||||
{
|
||||
listitem_T *item;
|
||||
@ -748,7 +748,7 @@ list_flatten(list_T *list, long maxdepth)
|
||||
int n;
|
||||
|
||||
if (maxdepth == 0)
|
||||
return OK;
|
||||
return;
|
||||
CHECK_LIST_MATERIALIZE(list);
|
||||
|
||||
n = 0;
|
||||
@ -757,7 +757,7 @@ list_flatten(list_T *list, long maxdepth)
|
||||
{
|
||||
fast_breakcheck();
|
||||
if (got_int)
|
||||
return FAIL;
|
||||
return;
|
||||
|
||||
if (item->li_tv.v_type == VAR_LIST)
|
||||
{
|
||||
@ -765,7 +765,7 @@ list_flatten(list_T *list, long maxdepth)
|
||||
|
||||
vimlist_remove(list, item, item);
|
||||
if (list_extend(list, item->li_tv.vval.v_list, next) == FAIL)
|
||||
return FAIL;
|
||||
return;
|
||||
clear_tv(&item->li_tv);
|
||||
tofree = item;
|
||||
|
||||
@ -787,15 +787,13 @@ list_flatten(list_T *list, long maxdepth)
|
||||
item = item->li_next;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* "flatten(list[, {maxdepth}])" function
|
||||
* "flatten()" and "flattennew()" functions
|
||||
*/
|
||||
void
|
||||
f_flatten(typval_T *argvars, typval_T *rettv)
|
||||
static void
|
||||
flatten_common(typval_T *argvars, typval_T *rettv, int make_copy)
|
||||
{
|
||||
list_T *l;
|
||||
long maxdepth;
|
||||
@ -822,10 +820,48 @@ f_flatten(typval_T *argvars, typval_T *rettv)
|
||||
}
|
||||
|
||||
l = argvars[0].vval.v_list;
|
||||
if (l != NULL && !value_check_lock(l->lv_lock,
|
||||
(char_u *)N_("flatten() argument"), TRUE)
|
||||
&& list_flatten(l, maxdepth) == OK)
|
||||
copy_tv(&argvars[0], rettv);
|
||||
rettv->v_type = VAR_LIST;
|
||||
rettv->vval.v_list = l;
|
||||
if (l == NULL)
|
||||
return;
|
||||
|
||||
if (make_copy)
|
||||
{
|
||||
l = list_copy(l, TRUE, get_copyID());
|
||||
rettv->vval.v_list = l;
|
||||
if (l == NULL)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value_check_lock(l->lv_lock,
|
||||
(char_u *)N_("flatten() argument"), TRUE))
|
||||
return;
|
||||
++l->lv_refcount;
|
||||
}
|
||||
|
||||
list_flatten(l, maxdepth);
|
||||
}
|
||||
|
||||
/*
|
||||
* "flatten(list[, {maxdepth}])" function
|
||||
*/
|
||||
void
|
||||
f_flatten(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
if (in_vim9script())
|
||||
emsg(_(e_cannot_use_flatten_in_vim9_script));
|
||||
else
|
||||
flatten_common(argvars, rettv, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* "flattennew(list[, {maxdepth}])" function
|
||||
*/
|
||||
void
|
||||
f_flattennew(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
flatten_common(argvars, rettv, TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -31,6 +31,7 @@ int list_append_number(list_T *l, varnumber_T n);
|
||||
int list_insert_tv(list_T *l, typval_T *tv, listitem_T *item);
|
||||
void list_insert(list_T *l, listitem_T *ni, listitem_T *item);
|
||||
void f_flatten(typval_T *argvars, typval_T *rettv);
|
||||
void f_flattennew(typval_T *argvars, typval_T *rettv);
|
||||
int list_extend(list_T *l1, list_T *l2, listitem_T *bef);
|
||||
int list_concat(list_T *l1, list_T *l2, typval_T *tv);
|
||||
list_T *list_slice(list_T *ol, long n1, long n2);
|
||||
|
@ -81,4 +81,13 @@ func Test_flatten()
|
||||
call assert_equal([2, l:x], l:y)
|
||||
endfunc
|
||||
|
||||
func Test_flattennew()
|
||||
let l = [1, [2, [3, 4]], 5]
|
||||
call assert_equal([1, 2, 3, 4, 5], flattennew(l))
|
||||
call assert_equal([1, [2, [3, 4]], 5], l)
|
||||
|
||||
call assert_equal([1, 2, [3, 4], 5], flattennew(l, 1))
|
||||
call assert_equal([1, [2, [3, 4]], 5], l)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -382,6 +382,23 @@ def Test_findfile()
|
||||
CheckDefExecFailure(['echo findfile("")'], 'E1142:')
|
||||
enddef
|
||||
|
||||
def Test_flattennew()
|
||||
var lines =<< trim END
|
||||
var l = [1, [2, [3, 4]], 5]
|
||||
call assert_equal([1, 2, 3, 4, 5], flattennew(l))
|
||||
call assert_equal([1, [2, [3, 4]], 5], l)
|
||||
|
||||
call assert_equal([1, 2, [3, 4], 5], flattennew(l, 1))
|
||||
call assert_equal([1, [2, [3, 4]], 5], l)
|
||||
END
|
||||
CheckDefAndScriptSuccess(lines)
|
||||
|
||||
lines =<< trim END
|
||||
echo flatten([1, 2, 3])
|
||||
END
|
||||
CheckDefAndScriptFailure(lines, 'E1158:')
|
||||
enddef
|
||||
|
||||
def Test_fnamemodify()
|
||||
CheckDefSuccess(['echo fnamemodify(test_null_string(), ":p")'])
|
||||
CheckDefSuccess(['echo fnamemodify("", ":p")'])
|
||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2449,
|
||||
/**/
|
||||
2448,
|
||||
/**/
|
||||
|
@ -2900,6 +2900,12 @@ compile_call(
|
||||
idx = find_internal_func(name);
|
||||
if (idx >= 0)
|
||||
{
|
||||
if (STRCMP(name, "flatten") == 0)
|
||||
{
|
||||
emsg(_(e_cannot_use_flatten_in_vim9_script));
|
||||
goto theend;
|
||||
}
|
||||
|
||||
if (STRCMP(name, "add") == 0 && argcount == 2)
|
||||
{
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
|
Loading…
x
Reference in New Issue
Block a user