Problem: Vim9: flatten() always changes the list type.
Solution: Disallow using flatten() and add flattennew().
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}
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.
: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.
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
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"));
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,
* 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;
int n;
if (maxdepth == 0)
- return OK;
+ return;
CHECK_LIST_MATERIALIZE(list);
n = 0;
{
fast_breakcheck();
if (got_int)
- return FAIL;
+ return;
if (item->li_tv.v_type == VAR_LIST)
{
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;
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;
}
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);
}
/*
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);
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
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")'])
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2449,
/**/
2448,
/**/
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;