forked from aniani/vim
patch 8.2.1969: Vim9: map() may change the list or dict item type
Problem: Vim9: map() may change the list or dict item type. Solution: Add mapnew().
This commit is contained in:
parent
8cebd43e97
commit
ea696852e7
@ -2669,8 +2669,9 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]])
|
|||||||
rhs of mapping {name} in mode {mode}
|
rhs of mapping {name} in mode {mode}
|
||||||
mapcheck({name} [, {mode} [, {abbr}]])
|
mapcheck({name} [, {mode} [, {abbr}]])
|
||||||
String check for mappings matching {name}
|
String check for mappings matching {name}
|
||||||
mapset({mode}, {abbr}, {dict})
|
mapnew({expr1}, {expr2}) List/Dict like |map()| but creates a new List
|
||||||
none restore mapping from |maparg()| result
|
or Dictionary
|
||||||
|
mapset({mode}, {abbr}, {dict}) none restore mapping from |maparg()| result
|
||||||
match({expr}, {pat} [, {start} [, {count}]])
|
match({expr}, {pat} [, {start} [, {count}]])
|
||||||
Number position where {pat} matches in {expr}
|
Number position where {pat} matches in {expr}
|
||||||
matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
|
matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]])
|
||||||
@ -6987,9 +6988,14 @@ luaeval({expr} [, {expr}]) *luaeval()*
|
|||||||
< {only available when compiled with the |+lua| feature}
|
< {only available when compiled with the |+lua| feature}
|
||||||
|
|
||||||
map({expr1}, {expr2}) *map()*
|
map({expr1}, {expr2}) *map()*
|
||||||
{expr1} must be a |List| or a |Dictionary|.
|
{expr1} must be a |List|, |Blob| or |Dictionary|.
|
||||||
Replace each item in {expr1} with the result of evaluating
|
Replace each item in {expr1} with the result of evaluating
|
||||||
{expr2}. {expr2} must be a |string| or |Funcref|.
|
{expr2}. For a |Blob| each byte is replaced.
|
||||||
|
If the item type changes you may want to use |mapnew()| to
|
||||||
|
create a new List or Dictionary. This is required when using
|
||||||
|
Vim9 script.
|
||||||
|
|
||||||
|
{expr2} must be a |string| or |Funcref|.
|
||||||
|
|
||||||
If {expr2} is a |string|, inside {expr2} |v:val| has the value
|
If {expr2} is a |string|, inside {expr2} |v:val| has the value
|
||||||
of the current item. For a |Dictionary| |v:key| has the key
|
of the current item. For a |Dictionary| |v:key| has the key
|
||||||
@ -7024,11 +7030,11 @@ map({expr1}, {expr2}) *map()*
|
|||||||
|Dictionary| to remain unmodified make a copy first: >
|
|Dictionary| to remain unmodified make a copy first: >
|
||||||
:let tlist = map(copy(mylist), ' v:val . "\t"')
|
:let tlist = map(copy(mylist), ' v:val . "\t"')
|
||||||
|
|
||||||
< Returns {expr1}, the |List| or |Dictionary| that was filtered.
|
< Returns {expr1}, the |List|, |Blob| or |Dictionary| that was
|
||||||
When an error is encountered while evaluating {expr2} no
|
filtered. When an error is encountered while evaluating
|
||||||
further items in {expr1} are processed. When {expr2} is a
|
{expr2} no further items in {expr1} are processed. When
|
||||||
Funcref errors inside a function are ignored, unless it was
|
{expr2} is a Funcref errors inside a function are ignored,
|
||||||
defined with the "abort" flag.
|
unless it was defined with the "abort" flag.
|
||||||
|
|
||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
mylist->map(expr2)
|
mylist->map(expr2)
|
||||||
@ -7137,6 +7143,12 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()*
|
|||||||
GetKey()->mapcheck('n')
|
GetKey()->mapcheck('n')
|
||||||
|
|
||||||
|
|
||||||
|
mapnew({expr1}, {expr2}) *mapnew()*
|
||||||
|
Like |map()| but instead of replacing items in {expr1} a new
|
||||||
|
List or Dictionary is created and returned. {expr1} remains
|
||||||
|
unchanged.
|
||||||
|
|
||||||
|
|
||||||
mapset({mode}, {abbr}, {dict}) *mapset()*
|
mapset({mode}, {abbr}, {dict}) *mapset()*
|
||||||
Restore a mapping from a dictionary returned by |maparg()|.
|
Restore a mapping from a dictionary returned by |maparg()|.
|
||||||
{mode} and {abbr} should be the same as for the call to
|
{mode} and {abbr} should be the same as for the call to
|
||||||
|
@ -644,6 +644,7 @@ List manipulation: *list-functions*
|
|||||||
deepcopy() make a full copy of a List
|
deepcopy() make a full copy of a List
|
||||||
filter() remove selected items from a List
|
filter() remove selected items from a List
|
||||||
map() change each List item
|
map() change each List item
|
||||||
|
mapnew() make a new List with changed items
|
||||||
reduce() reduce a List to a value
|
reduce() reduce a List to a value
|
||||||
sort() sort a List
|
sort() sort a List
|
||||||
reverse() reverse the order of a List
|
reverse() reverse the order of a List
|
||||||
@ -669,6 +670,7 @@ Dictionary manipulation: *dict-functions*
|
|||||||
extend() add entries from one Dictionary to another
|
extend() add entries from one Dictionary to another
|
||||||
filter() remove selected entries from a Dictionary
|
filter() remove selected entries from a Dictionary
|
||||||
map() change each Dictionary entry
|
map() change each Dictionary entry
|
||||||
|
mapnew() make a new Dictionary with changed items
|
||||||
keys() get List of Dictionary keys
|
keys() get List of Dictionary keys
|
||||||
values() get List of Dictionary values
|
values() get List of Dictionary values
|
||||||
items() get List of Dictionary key-value pairs
|
items() get List of Dictionary key-value pairs
|
||||||
|
@ -479,7 +479,6 @@ ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
|
|||||||
{
|
{
|
||||||
return &t_job;
|
return &t_job;
|
||||||
}
|
}
|
||||||
|
|
||||||
static type_T *
|
static type_T *
|
||||||
ret_first_arg(int argcount, type_T **argtypes)
|
ret_first_arg(int argcount, type_T **argtypes)
|
||||||
{
|
{
|
||||||
@ -487,6 +486,18 @@ ret_first_arg(int argcount, type_T **argtypes)
|
|||||||
return argtypes[0];
|
return argtypes[0];
|
||||||
return &t_void;
|
return &t_void;
|
||||||
}
|
}
|
||||||
|
// for map(): returns first argument but item type may differ
|
||||||
|
static type_T *
|
||||||
|
ret_first_cont(int argcount UNUSED, type_T **argtypes)
|
||||||
|
{
|
||||||
|
if (argtypes[0]->tt_type == VAR_LIST)
|
||||||
|
return &t_list_any;
|
||||||
|
if (argtypes[0]->tt_type == VAR_DICT)
|
||||||
|
return &t_dict_any;
|
||||||
|
if (argtypes[0]->tt_type == VAR_BLOB)
|
||||||
|
return argtypes[0];
|
||||||
|
return &t_any;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used for getqflist(): returns list if there is no argument, dict if there is
|
* Used for getqflist(): returns list if there is no argument, dict if there is
|
||||||
@ -1115,11 +1126,13 @@ static funcentry_T global_functions[] =
|
|||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
{"map", 2, 2, FEARG_1, NULL,
|
{"map", 2, 2, FEARG_1, NULL,
|
||||||
ret_any, f_map},
|
ret_first_cont, f_map},
|
||||||
{"maparg", 1, 4, FEARG_1, NULL,
|
{"maparg", 1, 4, FEARG_1, NULL,
|
||||||
ret_maparg, f_maparg},
|
ret_maparg, f_maparg},
|
||||||
{"mapcheck", 1, 3, FEARG_1, NULL,
|
{"mapcheck", 1, 3, FEARG_1, NULL,
|
||||||
ret_string, f_mapcheck},
|
ret_string, f_mapcheck},
|
||||||
|
{"mapnew", 2, 2, FEARG_1, NULL,
|
||||||
|
ret_first_cont, f_mapnew},
|
||||||
{"mapset", 3, 3, FEARG_1, NULL,
|
{"mapset", 3, 3, FEARG_1, NULL,
|
||||||
ret_void, f_mapset},
|
ret_void, f_mapset},
|
||||||
{"match", 2, 4, FEARG_1, NULL,
|
{"match", 2, 4, FEARG_1, NULL,
|
||||||
|
175
src/list.c
175
src/list.c
@ -1903,38 +1903,42 @@ f_uniq(typval_T *argvars, typval_T *rettv)
|
|||||||
do_sort_uniq(argvars, rettv, FALSE);
|
do_sort_uniq(argvars, rettv, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FILTERMAP_FILTER,
|
||||||
|
FILTERMAP_MAP,
|
||||||
|
FILTERMAP_MAPNEW
|
||||||
|
} filtermap_T;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle one item for map() and filter().
|
* Handle one item for map() and filter().
|
||||||
|
* Sets v:val to "tv". Caller must set v:key.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
|
filter_map_one(
|
||||||
|
typval_T *tv, // original value
|
||||||
|
typval_T *expr, // callback
|
||||||
|
filtermap_T filtermap,
|
||||||
|
typval_T *newtv, // for map() and mapnew(): new value
|
||||||
|
int *remp) // for filter(): remove flag
|
||||||
{
|
{
|
||||||
typval_T rettv;
|
|
||||||
typval_T argv[3];
|
typval_T argv[3];
|
||||||
int retval = FAIL;
|
int retval = FAIL;
|
||||||
|
|
||||||
copy_tv(tv, get_vim_var_tv(VV_VAL));
|
copy_tv(tv, get_vim_var_tv(VV_VAL));
|
||||||
argv[0] = *get_vim_var_tv(VV_KEY);
|
argv[0] = *get_vim_var_tv(VV_KEY);
|
||||||
argv[1] = *get_vim_var_tv(VV_VAL);
|
argv[1] = *get_vim_var_tv(VV_VAL);
|
||||||
if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
|
if (eval_expr_typval(expr, argv, 2, newtv) == FAIL)
|
||||||
goto theend;
|
goto theend;
|
||||||
if (map)
|
if (filtermap == FILTERMAP_FILTER)
|
||||||
{
|
|
||||||
// map(): replace the list item value
|
|
||||||
clear_tv(tv);
|
|
||||||
rettv.v_lock = 0;
|
|
||||||
*tv = rettv;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
int error = FALSE;
|
int error = FALSE;
|
||||||
|
|
||||||
// filter(): when expr is zero remove the item
|
// filter(): when expr is zero remove the item
|
||||||
if (in_vim9script())
|
if (in_vim9script())
|
||||||
*remp = !tv2bool(&rettv);
|
*remp = !tv2bool(newtv);
|
||||||
else
|
else
|
||||||
*remp = (tv_get_number_chk(&rettv, &error) == 0);
|
*remp = (tv_get_number_chk(newtv, &error) == 0);
|
||||||
clear_tv(&rettv);
|
clear_tv(newtv);
|
||||||
// On type error, nothing has been removed; return FAIL to stop the
|
// On type error, nothing has been removed; return FAIL to stop the
|
||||||
// loop. The error message was given by tv_get_number_chk().
|
// loop. The error message was given by tv_get_number_chk().
|
||||||
if (error)
|
if (error)
|
||||||
@ -1950,7 +1954,7 @@ theend:
|
|||||||
* Implementation of map() and filter().
|
* Implementation of map() and filter().
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
filter_map(typval_T *argvars, typval_T *rettv, int map)
|
filter_map(typval_T *argvars, typval_T *rettv, filtermap_T filtermap)
|
||||||
{
|
{
|
||||||
typval_T *expr;
|
typval_T *expr;
|
||||||
listitem_T *li, *nli;
|
listitem_T *li, *nli;
|
||||||
@ -1962,30 +1966,53 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
|
|||||||
blob_T *b = NULL;
|
blob_T *b = NULL;
|
||||||
int rem;
|
int rem;
|
||||||
int todo;
|
int todo;
|
||||||
char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
|
char_u *ermsg = (char_u *)(filtermap == FILTERMAP_MAP ? "map()"
|
||||||
char_u *arg_errmsg = (char_u *)(map ? N_("map() argument")
|
: filtermap == FILTERMAP_MAPNEW ? "mapnew()"
|
||||||
|
: "filter()");
|
||||||
|
char_u *arg_errmsg = (char_u *)(filtermap == FILTERMAP_MAP
|
||||||
|
? N_("map() argument")
|
||||||
|
: filtermap == FILTERMAP_MAPNEW
|
||||||
|
? N_("mapnew() argument")
|
||||||
: N_("filter() argument"));
|
: N_("filter() argument"));
|
||||||
int save_did_emsg;
|
int save_did_emsg;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
// Always return the first argument, also on failure.
|
// map() and filter() return the first argument, also on failure.
|
||||||
|
if (filtermap != FILTERMAP_MAPNEW)
|
||||||
copy_tv(&argvars[0], rettv);
|
copy_tv(&argvars[0], rettv);
|
||||||
|
|
||||||
if (argvars[0].v_type == VAR_BLOB)
|
if (argvars[0].v_type == VAR_BLOB)
|
||||||
{
|
{
|
||||||
|
if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
rettv->v_type = VAR_BLOB;
|
||||||
|
rettv->vval.v_blob = NULL;
|
||||||
|
}
|
||||||
if ((b = argvars[0].vval.v_blob) == NULL)
|
if ((b = argvars[0].vval.v_blob) == NULL)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (argvars[0].v_type == VAR_LIST)
|
else if (argvars[0].v_type == VAR_LIST)
|
||||||
{
|
{
|
||||||
|
if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
rettv->v_type = VAR_LIST;
|
||||||
|
rettv->vval.v_list = NULL;
|
||||||
|
}
|
||||||
if ((l = argvars[0].vval.v_list) == NULL
|
if ((l = argvars[0].vval.v_list) == NULL
|
||||||
|| (!map && value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
|
|| (filtermap == FILTERMAP_FILTER
|
||||||
|
&& value_check_lock(l->lv_lock, arg_errmsg, TRUE)))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (argvars[0].v_type == VAR_DICT)
|
else if (argvars[0].v_type == VAR_DICT)
|
||||||
{
|
{
|
||||||
|
if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
rettv->v_type = VAR_DICT;
|
||||||
|
rettv->vval.v_dict = NULL;
|
||||||
|
}
|
||||||
if ((d = argvars[0].vval.v_dict) == NULL
|
if ((d = argvars[0].vval.v_dict) == NULL
|
||||||
|| (!map && value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
|
|| (filtermap == FILTERMAP_FILTER
|
||||||
|
&& value_check_lock(d->dv_lock, arg_errmsg, TRUE)))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2014,8 +2041,16 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
|
|||||||
if (argvars[0].v_type == VAR_DICT)
|
if (argvars[0].v_type == VAR_DICT)
|
||||||
{
|
{
|
||||||
int prev_lock = d->dv_lock;
|
int prev_lock = d->dv_lock;
|
||||||
|
dict_T *d_ret = NULL;
|
||||||
|
|
||||||
if (map && d->dv_lock == 0)
|
if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
if (rettv_dict_alloc(rettv) == FAIL)
|
||||||
|
return;
|
||||||
|
d_ret = rettv->vval.v_dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filtermap != FILTERMAP_FILTER && d->dv_lock == 0)
|
||||||
d->dv_lock = VAR_LOCKED;
|
d->dv_lock = VAR_LOCKED;
|
||||||
ht = &d->dv_hashtab;
|
ht = &d->dv_hashtab;
|
||||||
hash_lock(ht);
|
hash_lock(ht);
|
||||||
@ -2025,21 +2060,43 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
|
|||||||
if (!HASHITEM_EMPTY(hi))
|
if (!HASHITEM_EMPTY(hi))
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
typval_T newtv;
|
||||||
|
|
||||||
--todo;
|
--todo;
|
||||||
di = HI2DI(hi);
|
di = HI2DI(hi);
|
||||||
if (map && (value_check_lock(di->di_tv.v_lock,
|
if (filtermap != FILTERMAP_FILTER
|
||||||
|
&& (value_check_lock(di->di_tv.v_lock,
|
||||||
arg_errmsg, TRUE)
|
arg_errmsg, TRUE)
|
||||||
|| var_check_ro(di->di_flags,
|
|| var_check_ro(di->di_flags,
|
||||||
arg_errmsg, TRUE)))
|
arg_errmsg, TRUE)))
|
||||||
break;
|
break;
|
||||||
set_vim_var_string(VV_KEY, di->di_key, -1);
|
set_vim_var_string(VV_KEY, di->di_key, -1);
|
||||||
r = filter_map_one(&di->di_tv, expr, map, &rem);
|
r = filter_map_one(&di->di_tv, expr, filtermap,
|
||||||
|
&newtv, &rem);
|
||||||
clear_tv(get_vim_var_tv(VV_KEY));
|
clear_tv(get_vim_var_tv(VV_KEY));
|
||||||
if (r == FAIL || did_emsg)
|
if (r == FAIL || did_emsg)
|
||||||
break;
|
|
||||||
if (!map && rem)
|
|
||||||
{
|
{
|
||||||
|
clear_tv(&newtv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (filtermap == FILTERMAP_MAP)
|
||||||
|
{
|
||||||
|
// map(): replace the dict item value
|
||||||
|
clear_tv(&di->di_tv);
|
||||||
|
newtv.v_lock = 0;
|
||||||
|
di->di_tv = newtv;
|
||||||
|
}
|
||||||
|
else if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
// mapnew(): add the item value to the new dict
|
||||||
|
r = dict_add_tv(d_ret, (char *)di->di_key, &newtv);
|
||||||
|
clear_tv(&newtv);
|
||||||
|
if (r == FAIL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (filtermap == FILTERMAP_FILTER && rem)
|
||||||
|
{
|
||||||
|
// filter(false): remove the item from the dict
|
||||||
if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
|
if (var_check_fixed(di->di_flags, arg_errmsg, TRUE)
|
||||||
|| var_check_ro(di->di_flags, arg_errmsg, TRUE))
|
|| var_check_ro(di->di_flags, arg_errmsg, TRUE))
|
||||||
break;
|
break;
|
||||||
@ -2055,27 +2112,39 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
|
|||||||
int i;
|
int i;
|
||||||
typval_T tv;
|
typval_T tv;
|
||||||
varnumber_T val;
|
varnumber_T val;
|
||||||
|
blob_T *b_ret = b;
|
||||||
|
|
||||||
|
if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
if (blob_copy(b, rettv) == FAIL)
|
||||||
|
return;
|
||||||
|
b_ret = rettv->vval.v_blob;
|
||||||
|
}
|
||||||
|
|
||||||
// set_vim_var_nr() doesn't set the type
|
// set_vim_var_nr() doesn't set the type
|
||||||
set_vim_var_type(VV_KEY, VAR_NUMBER);
|
set_vim_var_type(VV_KEY, VAR_NUMBER);
|
||||||
|
|
||||||
for (i = 0; i < b->bv_ga.ga_len; i++)
|
for (i = 0; i < b->bv_ga.ga_len; i++)
|
||||||
{
|
{
|
||||||
|
typval_T newtv;
|
||||||
|
|
||||||
tv.v_type = VAR_NUMBER;
|
tv.v_type = VAR_NUMBER;
|
||||||
val = blob_get(b, i);
|
val = blob_get(b, i);
|
||||||
tv.vval.v_number = val;
|
tv.vval.v_number = val;
|
||||||
set_vim_var_nr(VV_KEY, idx);
|
set_vim_var_nr(VV_KEY, idx);
|
||||||
if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
|
if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
|
||||||
|
|| did_emsg)
|
||||||
break;
|
break;
|
||||||
if (tv.v_type != VAR_NUMBER)
|
if (newtv.v_type != VAR_NUMBER)
|
||||||
{
|
{
|
||||||
|
clear_tv(&newtv);
|
||||||
emsg(_(e_invalblob));
|
emsg(_(e_invalblob));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (map)
|
if (filtermap != FILTERMAP_FILTER)
|
||||||
{
|
{
|
||||||
if (tv.vval.v_number != val)
|
if (newtv.vval.v_number != val)
|
||||||
blob_set(b, i, tv.vval.v_number);
|
blob_set(b_ret, i, newtv.vval.v_number);
|
||||||
}
|
}
|
||||||
else if (rem)
|
else if (rem)
|
||||||
{
|
{
|
||||||
@ -2092,23 +2161,46 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
|
|||||||
else // argvars[0].v_type == VAR_LIST
|
else // argvars[0].v_type == VAR_LIST
|
||||||
{
|
{
|
||||||
int prev_lock = l->lv_lock;
|
int prev_lock = l->lv_lock;
|
||||||
|
list_T *l_ret = NULL;
|
||||||
|
|
||||||
|
if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
if (rettv_list_alloc(rettv) == FAIL)
|
||||||
|
return;
|
||||||
|
l_ret = rettv->vval.v_list;
|
||||||
|
}
|
||||||
// set_vim_var_nr() doesn't set the type
|
// set_vim_var_nr() doesn't set the type
|
||||||
set_vim_var_type(VV_KEY, VAR_NUMBER);
|
set_vim_var_type(VV_KEY, VAR_NUMBER);
|
||||||
|
|
||||||
CHECK_LIST_MATERIALIZE(l);
|
CHECK_LIST_MATERIALIZE(l);
|
||||||
if (map && l->lv_lock == 0)
|
if (filtermap != FILTERMAP_FILTER && l->lv_lock == 0)
|
||||||
l->lv_lock = VAR_LOCKED;
|
l->lv_lock = VAR_LOCKED;
|
||||||
for (li = l->lv_first; li != NULL; li = nli)
|
for (li = l->lv_first; li != NULL; li = nli)
|
||||||
{
|
{
|
||||||
if (map && value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
|
typval_T newtv;
|
||||||
|
|
||||||
|
if (filtermap != FILTERMAP_FILTER
|
||||||
|
&& value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
|
||||||
break;
|
break;
|
||||||
nli = li->li_next;
|
nli = li->li_next;
|
||||||
set_vim_var_nr(VV_KEY, idx);
|
set_vim_var_nr(VV_KEY, idx);
|
||||||
if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
|
if (filter_map_one(&li->li_tv, expr, filtermap,
|
||||||
|| did_emsg)
|
&newtv, &rem) == FAIL || did_emsg)
|
||||||
break;
|
break;
|
||||||
if (!map && rem)
|
if (filtermap == FILTERMAP_MAP)
|
||||||
|
{
|
||||||
|
// map(): replace the list item value
|
||||||
|
clear_tv(&li->li_tv);
|
||||||
|
newtv.v_lock = 0;
|
||||||
|
li->li_tv = newtv;
|
||||||
|
}
|
||||||
|
else if (filtermap == FILTERMAP_MAPNEW)
|
||||||
|
{
|
||||||
|
// mapnew(): append the list item value
|
||||||
|
if (list_append_tv_move(l_ret, &newtv) == FAIL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (filtermap == FILTERMAP_FILTER && rem)
|
||||||
listitem_remove(l, li);
|
listitem_remove(l, li);
|
||||||
++idx;
|
++idx;
|
||||||
}
|
}
|
||||||
@ -2128,7 +2220,7 @@ filter_map(typval_T *argvars, typval_T *rettv, int map)
|
|||||||
void
|
void
|
||||||
f_filter(typval_T *argvars, typval_T *rettv)
|
f_filter(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
filter_map(argvars, rettv, FALSE);
|
filter_map(argvars, rettv, FILTERMAP_FILTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2137,7 +2229,16 @@ f_filter(typval_T *argvars, typval_T *rettv)
|
|||||||
void
|
void
|
||||||
f_map(typval_T *argvars, typval_T *rettv)
|
f_map(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
filter_map(argvars, rettv, TRUE);
|
filter_map(argvars, rettv, FILTERMAP_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "mapnew()" function
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
f_mapnew(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
filter_map(argvars, rettv, FILTERMAP_MAPNEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -48,6 +48,7 @@ void f_sort(typval_T *argvars, typval_T *rettv);
|
|||||||
void f_uniq(typval_T *argvars, typval_T *rettv);
|
void f_uniq(typval_T *argvars, typval_T *rettv);
|
||||||
void f_filter(typval_T *argvars, typval_T *rettv);
|
void f_filter(typval_T *argvars, typval_T *rettv);
|
||||||
void f_map(typval_T *argvars, typval_T *rettv);
|
void f_map(typval_T *argvars, typval_T *rettv);
|
||||||
|
void f_mapnew(typval_T *argvars, typval_T *rettv);
|
||||||
void f_add(typval_T *argvars, typval_T *rettv);
|
void f_add(typval_T *argvars, typval_T *rettv);
|
||||||
void f_count(typval_T *argvars, typval_T *rettv);
|
void f_count(typval_T *argvars, typval_T *rettv);
|
||||||
void f_extend(typval_T *argvars, typval_T *rettv);
|
void f_extend(typval_T *argvars, typval_T *rettv);
|
||||||
|
@ -118,4 +118,25 @@ func Test_map_and_modify()
|
|||||||
call assert_fails('echo map(d, {k,v -> remove(d, k)})', 'E741:')
|
call assert_fails('echo map(d, {k,v -> remove(d, k)})', 'E741:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_mapnew_dict()
|
||||||
|
let din = #{one: 1, two: 2}
|
||||||
|
let dout = mapnew(din, {k, v -> string(v)})
|
||||||
|
call assert_equal(#{one: 1, two: 2}, din)
|
||||||
|
call assert_equal(#{one: '1', two: '2'}, dout)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_mapnew_list()
|
||||||
|
let lin = [1, 2, 3]
|
||||||
|
let lout = mapnew(lin, {k, v -> string(v)})
|
||||||
|
call assert_equal([1, 2, 3], lin)
|
||||||
|
call assert_equal(['1', '2', '3'], lout)
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_mapnew_blob()
|
||||||
|
let bin = 0z123456
|
||||||
|
let bout = mapnew(bin, {k, v -> k == 1 ? 0x99 : v})
|
||||||
|
call assert_equal(0z123456, bin)
|
||||||
|
call assert_equal(0z129956, bout)
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -750,6 +750,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 */
|
||||||
|
/**/
|
||||||
|
1969,
|
||||||
/**/
|
/**/
|
||||||
1968,
|
1968,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user