mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.2.2336: Vim9: not possible to extend dictionary with different type (#22425)
Problem: Vim9: it is not possible to extend a dictionary with different
item types.
Solution: Add extendnew(). (closes vim/vim#7666)
b0e6b51364
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
parent
d52a3f7c71
commit
2c9fbe34b2
@ -138,6 +138,9 @@ expandcmd({string} [, {options}])
|
|||||||
String expand {string} like with `:edit`
|
String expand {string} like with `:edit`
|
||||||
extend({expr1}, {expr2} [, {expr3}])
|
extend({expr1}, {expr2} [, {expr3}])
|
||||||
List/Dict insert items of {expr2} into {expr1}
|
List/Dict insert items of {expr2} into {expr1}
|
||||||
|
extendnew({expr1}, {expr2} [, {expr3}])
|
||||||
|
List/Dict like |extend()| but creates a new
|
||||||
|
List or Dictionary
|
||||||
feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer
|
feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer
|
||||||
filereadable({file}) Number |TRUE| if {file} is a readable file
|
filereadable({file}) Number |TRUE| if {file} is a readable file
|
||||||
filewritable({file}) Number |TRUE| if {file} is a writable file
|
filewritable({file}) Number |TRUE| if {file} is a writable file
|
||||||
@ -2119,6 +2122,14 @@ extend({expr1}, {expr2} [, {expr3}]) *extend()*
|
|||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
mylist->extend(otherlist)
|
mylist->extend(otherlist)
|
||||||
|
|
||||||
|
|
||||||
|
extendnew({expr1}, {expr2} [, {expr3}]) *extendnew()*
|
||||||
|
Like |extend()| but instead of adding items to {expr1} a new
|
||||||
|
List or Dictionary is created and returned. {expr1} remains
|
||||||
|
unchanged. Items can still be changed by {expr2}, if you
|
||||||
|
don't want that use |deepcopy()| first.
|
||||||
|
|
||||||
|
|
||||||
feedkeys({string} [, {mode}]) *feedkeys()*
|
feedkeys({string} [, {mode}]) *feedkeys()*
|
||||||
Characters in {string} are queued for processing as if they
|
Characters in {string} are queued for processing as if they
|
||||||
come from a mapping or were typed by the user.
|
come from a mapping or were typed by the user.
|
||||||
|
@ -650,6 +650,7 @@ List manipulation: *list-functions*
|
|||||||
insert() insert an item somewhere in a List
|
insert() insert an item somewhere in a List
|
||||||
add() append an item to a List
|
add() append an item to a List
|
||||||
extend() append a List to a List
|
extend() append a List to a List
|
||||||
|
extendnew() make a new List and append items
|
||||||
remove() remove one or more items from a List
|
remove() remove one or more items from a List
|
||||||
copy() make a shallow copy of a List
|
copy() make a shallow copy of a List
|
||||||
deepcopy() make a full copy of a List
|
deepcopy() make a full copy of a List
|
||||||
@ -681,6 +682,7 @@ Dictionary manipulation: *dict-functions*
|
|||||||
empty() check if Dictionary is empty
|
empty() check if Dictionary is empty
|
||||||
remove() remove an entry from a Dictionary
|
remove() remove an entry from a Dictionary
|
||||||
extend() add entries from one Dictionary to another
|
extend() add entries from one Dictionary to another
|
||||||
|
extendnew() make a new Dictionary and append items
|
||||||
filter() remove selected entries from a Dictionary
|
filter() remove selected entries from a Dictionary
|
||||||
map() change each Dictionary entry
|
map() change each Dictionary entry
|
||||||
keys() get List of Dictionary keys
|
keys() get List of Dictionary keys
|
||||||
|
@ -120,6 +120,7 @@ return {
|
|||||||
expand={args={1, 3}, base=1},
|
expand={args={1, 3}, base=1},
|
||||||
expandcmd={args={1, 2}, base=1},
|
expandcmd={args={1, 2}, base=1},
|
||||||
extend={args={2, 3}, base=1},
|
extend={args={2, 3}, base=1},
|
||||||
|
extendnew={args={2, 3}, base=1},
|
||||||
feedkeys={args={1, 2}, base=1},
|
feedkeys={args={1, 2}, base=1},
|
||||||
file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete
|
file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete
|
||||||
filereadable={args=1, base=1, fast=true},
|
filereadable={args=1, base=1, fast=true},
|
||||||
|
@ -1929,18 +1929,22 @@ static void f_flattennew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
flatten_common(argvars, rettv, true);
|
flatten_common(argvars, rettv, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "extend(list, list [, idx])" function
|
/// "extend()" or "extendnew()" function. "is_new" is true for extendnew().
|
||||||
/// "extend(dict, dict [, action])" function
|
static void extend(typval_T *argvars, typval_T *rettv, char *arg_errmsg, bool is_new)
|
||||||
static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|
||||||
{
|
{
|
||||||
const char *const arg_errmsg = N_("extend() argument");
|
|
||||||
|
|
||||||
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
|
if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST) {
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
list_T *const l1 = argvars[0].vval.v_list;
|
list_T *l1 = argvars[0].vval.v_list;
|
||||||
list_T *const l2 = argvars[1].vval.v_list;
|
list_T *const l2 = argvars[1].vval.v_list;
|
||||||
if (!value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
|
if (is_new || !value_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
|
||||||
|
if (is_new) {
|
||||||
|
l1 = tv_list_copy(NULL, l1, false, get_copyID());
|
||||||
|
if (l1 == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
listitem_T *item;
|
listitem_T *item;
|
||||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
long before = (long)tv_get_number_chk(&argvars[2], &error);
|
long before = (long)tv_get_number_chk(&argvars[2], &error);
|
||||||
@ -1962,11 +1966,18 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
}
|
}
|
||||||
tv_list_extend(l1, l2, item);
|
tv_list_extend(l1, l2, item);
|
||||||
|
|
||||||
tv_copy(&argvars[0], rettv);
|
if (is_new) {
|
||||||
|
*rettv = (typval_T){
|
||||||
|
.v_type = VAR_LIST,
|
||||||
|
.v_lock = VAR_UNLOCKED,
|
||||||
|
.vval.v_list = l1,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
tv_copy(&argvars[0], rettv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type ==
|
} else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT) {
|
||||||
VAR_DICT) {
|
dict_T *d1 = argvars[0].vval.v_dict;
|
||||||
dict_T *const d1 = argvars[0].vval.v_dict;
|
|
||||||
dict_T *const d2 = argvars[1].vval.v_dict;
|
dict_T *const d2 = argvars[1].vval.v_dict;
|
||||||
if (d1 == NULL) {
|
if (d1 == NULL) {
|
||||||
const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
|
const bool locked = value_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
|
||||||
@ -1975,7 +1986,14 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
} else if (d2 == NULL) {
|
} else if (d2 == NULL) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
tv_copy(&argvars[0], rettv);
|
tv_copy(&argvars[0], rettv);
|
||||||
} else if (!value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
|
} else if (is_new || !value_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
|
||||||
|
if (is_new) {
|
||||||
|
d1 = tv_dict_copy(NULL, d1, false, get_copyID());
|
||||||
|
if (d1 == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *action = "force";
|
const char *action = "force";
|
||||||
// Check the third argument.
|
// Check the third argument.
|
||||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||||
@ -1999,13 +2017,37 @@ static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
|
|
||||||
tv_dict_extend(d1, d2, action);
|
tv_dict_extend(d1, d2, action);
|
||||||
|
|
||||||
tv_copy(&argvars[0], rettv);
|
if (is_new) {
|
||||||
|
*rettv = (typval_T){
|
||||||
|
.v_type = VAR_DICT,
|
||||||
|
.v_lock = VAR_UNLOCKED,
|
||||||
|
.vval.v_dict = d1,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
tv_copy(&argvars[0], rettv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
semsg(_(e_listdictarg), "extend()");
|
semsg(_(e_listdictarg), is_new ? "extendnew()" : "extend()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// "extend(list, list [, idx])" function
|
||||||
|
/// "extend(dict, dict [, action])" function
|
||||||
|
static void f_extend(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
|
{
|
||||||
|
char *errmsg = N_("extend() argument");
|
||||||
|
extend(argvars, rettv, errmsg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// "extendnew(list, list [, idx])" function
|
||||||
|
/// "extendnew(dict, dict [, action])" function
|
||||||
|
static void f_extendnew(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
|
{
|
||||||
|
char *errmsg = N_("extendnew() argument");
|
||||||
|
extend(argvars, rettv, errmsg, true);
|
||||||
|
}
|
||||||
|
|
||||||
/// "feedkeys()" function
|
/// "feedkeys()" function
|
||||||
static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
static void f_feedkeys(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||||
{
|
{
|
||||||
|
@ -881,6 +881,18 @@ func Test_listdict_extend()
|
|||||||
call assert_equal([1, 5, 7, 1, 5, 7], l)
|
call assert_equal([1, 5, 7, 1, 5, 7], l)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_listdict_extendnew()
|
||||||
|
" Test extendnew() with lists
|
||||||
|
let l = [1, 2, 3]
|
||||||
|
call assert_equal([1, 2, 3, 4, 5], extendnew(l, [4, 5]))
|
||||||
|
call assert_equal([1, 2, 3], l)
|
||||||
|
|
||||||
|
" Test extend() with dictionaries.
|
||||||
|
let d = {'a': {'b': 'B'}}
|
||||||
|
call assert_equal({'a': {'b': 'B'}, 'c': 'cc'}, extendnew(d, {'c': 'cc'}))
|
||||||
|
call assert_equal({'a': {'b': 'B'}}, d)
|
||||||
|
endfunc
|
||||||
|
|
||||||
func s:check_scope_dict(x, fixed)
|
func s:check_scope_dict(x, fixed)
|
||||||
func s:gen_cmd(cmd, x)
|
func s:gen_cmd(cmd, x)
|
||||||
return substitute(a:cmd, '\<x\ze:', a:x, 'g')
|
return substitute(a:cmd, '\<x\ze:', a:x, 'g')
|
||||||
|
Loading…
Reference in New Issue
Block a user