mirror of
https://github.com/vim/vim.git
synced 2025-10-17 07:44:28 -04:00
patch 9.1.1668: items() does not work for Blobs
Problem: items() does not work for Blobs Solution: Extend items() to support Blob (Yegappan Lakshmanan). closes: #18080 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
6b56711804
commit
da34f84847
@@ -1,4 +1,4 @@
|
||||
*builtin.txt* For Vim version 9.1. Last change: 2025 Aug 20
|
||||
*builtin.txt* For Vim version 9.1. Last change: 2025 Aug 23
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -344,7 +344,7 @@ isinf({expr}) Number determine if {expr} is infinity value
|
||||
(positive or negative)
|
||||
islocked({expr}) Number |TRUE| if {expr} is locked
|
||||
isnan({expr}) Number |TRUE| if {expr} is NaN
|
||||
items({expr}) List key-value pairs in {expr}
|
||||
items({expr}) List key/index-value pairs in {expr}
|
||||
job_getchannel({job}) Channel get the channel handle for {job}
|
||||
job_info([{job}]) Dict get information about {job}
|
||||
job_setoptions({job}, {options}) none set options for {job}
|
||||
@@ -6314,7 +6314,8 @@ items({expr}) *items()*
|
||||
Return a |List| with all key/index and value pairs of {expr}.
|
||||
Each |List| item is a list with two items:
|
||||
- for a |Dict|: the key and the value
|
||||
- for a |List|, |Tuple| or |String|: the index and the value
|
||||
- for a |List|, |Tuple|, |Blob| or |String|: the index and the
|
||||
value
|
||||
The returned |List| is in arbitrary order for a |Dict|,
|
||||
otherwise it's in ascending order of the index.
|
||||
|
||||
@@ -6328,6 +6329,7 @@ items({expr}) *items()*
|
||||
echo items([1, 2, 3])
|
||||
echo items(('a', 'b', 'c'))
|
||||
echo items("foobar")
|
||||
echo items(0z0102)
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
mydict->items()
|
||||
|
@@ -1,4 +1,4 @@
|
||||
*usr_41.txt* For Vim version 9.1. Last change: 2025 Aug 18
|
||||
*usr_41.txt* For Vim version 9.1. Last change: 2025 Aug 23
|
||||
|
||||
VIM USER MANUAL - by Bram Moolenaar
|
||||
|
||||
@@ -920,6 +920,7 @@ Blob manipulation: *blob-functions*
|
||||
reverse() reverse the order of numbers in a blob
|
||||
index() index of a value in a Blob
|
||||
indexof() index in a Blob where an expression is true
|
||||
items() get List of Blob index-value pairs
|
||||
|
||||
Other computation: *bitwise-function*
|
||||
and() bitwise AND
|
||||
|
@@ -41648,6 +41648,8 @@ Other new features ~
|
||||
- Add the new default highlighting groups "Bold", "Italic" and "BoldItalic"
|
||||
for use in syntax scripts.
|
||||
|
||||
- |items()| function now supports Blob.
|
||||
|
||||
*changed-9.2*
|
||||
Changed~
|
||||
-------
|
||||
|
32
src/blob.c
32
src/blob.c
@@ -289,6 +289,38 @@ blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
|
||||
return *tofree;
|
||||
}
|
||||
|
||||
/*
|
||||
* "items(blob)" function
|
||||
* Converts a Blob into a List of [index, byte] pairs.
|
||||
* Caller must have already checked that argvars[0] is a Blob.
|
||||
* A null blob behaves like an empty blob.
|
||||
*/
|
||||
void
|
||||
blob2items(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
blob_T *blob = argvars[0].vval.v_blob;
|
||||
|
||||
if (rettv_list_alloc(rettv) == FAIL)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < blob_len(blob); i++)
|
||||
{
|
||||
list_T *l2 = list_alloc();
|
||||
if (l2 == NULL)
|
||||
return;
|
||||
|
||||
if (list_append_list(rettv->vval.v_list, l2) == FAIL)
|
||||
{
|
||||
vim_free(l2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (list_append_number(l2, i) == FAIL
|
||||
|| list_append_number(l2, blob_get(blob, i)) == FAIL)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a string variable, in the format of blob2string(), to a blob.
|
||||
* Return NULL when conversion failed.
|
||||
|
17
src/dict.c
17
src/dict.c
@@ -1557,9 +1557,7 @@ dict2list(typval_T *argvars, typval_T *rettv, dict2list_T what)
|
||||
if (rettv_list_alloc(rettv) == FAIL)
|
||||
return;
|
||||
|
||||
if ((what == DICT2LIST_ITEMS
|
||||
? check_for_string_list_tuple_or_dict_arg(argvars, 0)
|
||||
: check_for_dict_arg(argvars, 0)) == FAIL)
|
||||
if (check_for_dict_arg(argvars, 0) == FAIL)
|
||||
return;
|
||||
|
||||
d = argvars[0].vval.v_dict;
|
||||
@@ -1612,19 +1610,12 @@ dict2list(typval_T *argvars, typval_T *rettv, dict2list_T what)
|
||||
}
|
||||
|
||||
/*
|
||||
* "items(dict)" function
|
||||
* "items()" function
|
||||
*/
|
||||
void
|
||||
f_items(typval_T *argvars, typval_T *rettv)
|
||||
dict2items(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_STRING)
|
||||
string2items(argvars, rettv);
|
||||
else if (argvars[0].v_type == VAR_LIST)
|
||||
list2items(argvars, rettv);
|
||||
else if (argvars[0].v_type == VAR_TUPLE)
|
||||
tuple2items(argvars, rettv);
|
||||
else
|
||||
dict2list(argvars, rettv, DICT2LIST_ITEMS);
|
||||
dict2list(argvars, rettv, DICT2LIST_ITEMS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -97,6 +97,7 @@ static void f_inputsecret(typval_T *argvars, typval_T *rettv);
|
||||
static void f_interrupt(typval_T *argvars, typval_T *rettv);
|
||||
static void f_invert(typval_T *argvars, typval_T *rettv);
|
||||
static void f_islocked(typval_T *argvars, typval_T *rettv);
|
||||
static void f_items(typval_T *argvars, typval_T *rettv);
|
||||
static void f_keytrans(typval_T *argvars, typval_T *rettv);
|
||||
static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
|
||||
static void f_libcall(typval_T *argvars, typval_T *rettv);
|
||||
@@ -726,11 +727,12 @@ arg_list_tuple_dict_blob_or_string(
|
||||
|| type->tt_type == VAR_STRING
|
||||
|| type_any_or_unknown(type))
|
||||
return OK;
|
||||
arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
|
||||
|
||||
semsg(_(e_list_tuple_dict_blob_or_string_required_for_argument_nr),
|
||||
context->arg_idx + 1);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check second argument of map(), filter(), foreach().
|
||||
*/
|
||||
@@ -1248,7 +1250,7 @@ static argcheck_T arg1_list_number[] = {arg_list_number};
|
||||
static argcheck_T arg1_reverse[] = {arg_reverse};
|
||||
static argcheck_T arg1_list_or_tuple_or_dict[] = {arg_list_or_tuple_or_dict};
|
||||
static argcheck_T arg1_list_string[] = {arg_list_string};
|
||||
static argcheck_T arg1_string_list_tuple_or_dict[] = {arg_string_list_tuple_or_dict};
|
||||
static argcheck_T arg1_list_tuple_dict_blob_or_string[] = {arg_list_tuple_dict_blob_or_string};
|
||||
static argcheck_T arg1_lnum[] = {arg_lnum};
|
||||
static argcheck_T arg1_number[] = {arg_number};
|
||||
static argcheck_T arg1_string[] = {arg_string};
|
||||
@@ -2432,7 +2434,7 @@ static funcentry_T global_functions[] =
|
||||
ret_number_bool, f_islocked},
|
||||
{"isnan", 1, 1, FEARG_1, arg1_float_or_nr,
|
||||
ret_number_bool, MATH_FUNC(f_isnan)},
|
||||
{"items", 1, 1, FEARG_1, arg1_string_list_tuple_or_dict,
|
||||
{"items", 1, 1, FEARG_1, arg1_list_tuple_dict_blob_or_string,
|
||||
ret_list_items, f_items},
|
||||
{"job_getchannel", 1, 1, FEARG_1, arg1_job,
|
||||
ret_channel, JOB_FUNC(f_job_getchannel)},
|
||||
@@ -8716,6 +8718,26 @@ f_islocked(typval_T *argvars, typval_T *rettv)
|
||||
clear_lval(&lv);
|
||||
}
|
||||
|
||||
/*
|
||||
* "items(dict)" function
|
||||
*/
|
||||
static void
|
||||
f_items(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_STRING)
|
||||
string2items(argvars, rettv);
|
||||
else if (argvars[0].v_type == VAR_LIST)
|
||||
list2items(argvars, rettv);
|
||||
else if (argvars[0].v_type == VAR_TUPLE)
|
||||
tuple2items(argvars, rettv);
|
||||
else if (argvars[0].v_type == VAR_BLOB)
|
||||
blob2items(argvars, rettv);
|
||||
else if (argvars[0].v_type == VAR_DICT)
|
||||
dict2items(argvars, rettv);
|
||||
else
|
||||
semsg(_(e_list_tuple_dict_blob_or_string_required_for_argument_nr), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* "keytrans()" function
|
||||
*/
|
||||
|
@@ -13,6 +13,7 @@ int blob_equal(blob_T *b1, blob_T *b2);
|
||||
int read_blob(FILE *fd, typval_T *rettv, off_T offset, off_T size_arg);
|
||||
int write_blob(FILE *fd, blob_T *blob);
|
||||
char_u *blob2string(blob_T *blob, char_u **tofree, char_u *numbuf);
|
||||
void blob2items(typval_T *argvars, typval_T *rettv);
|
||||
blob_T *string2blob(char_u *str);
|
||||
int blob_slice_or_index(blob_T *blob, int is_range, varnumber_T n1, varnumber_T n2, int exclusive, typval_T *rettv);
|
||||
int check_blob_index(long bloblen, varnumber_T n1, int quiet);
|
||||
|
@@ -46,7 +46,7 @@ long dict_count(dict_T *d, typval_T *needle, int ic);
|
||||
void dict_extend_func(typval_T *argvars, type_T *type, char *func_name, char_u *arg_errmsg, int is_new, typval_T *rettv);
|
||||
void dict_filter_map(dict_T *d, filtermap_T filtermap, type_T *argtype, char *func_name, char_u *arg_errmsg, typval_T *expr, typval_T *rettv);
|
||||
void dict_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg);
|
||||
void f_items(typval_T *argvars, typval_T *rettv);
|
||||
void dict2items(typval_T *argvars, typval_T *rettv);
|
||||
void f_keys(typval_T *argvars, typval_T *rettv);
|
||||
void f_values(typval_T *argvars, typval_T *rettv);
|
||||
void dict_set_items_ro(dict_T *di);
|
||||
|
@@ -865,4 +865,15 @@ func Test_indexof()
|
||||
call assert_fails('let i = indexof(b, " ")', 'E15:')
|
||||
endfunc
|
||||
|
||||
" Test for using the items() function with a blob
|
||||
func Test_blob_items()
|
||||
let lines =<< trim END
|
||||
call assert_equal([[0, 0xAA], [1, 0xBB], [2, 0xCC]], 0zAABBCC->items())
|
||||
call assert_equal([[0, 0]], 0z00->items())
|
||||
call assert_equal([], 0z->items())
|
||||
call assert_equal([], test_null_blob()->items())
|
||||
END
|
||||
call v9.CheckSourceLegacyAndVim9Success(lines)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@@ -230,7 +230,7 @@ func Test_list_items()
|
||||
endfor
|
||||
call assert_equal([[0, 'a'], [1, 'b'], [2, 'c']], r)
|
||||
|
||||
call assert_fails('call items(3)', 'E1225:')
|
||||
call assert_fails('call items(3)', 'E1251:')
|
||||
endfunc
|
||||
|
||||
func Test_string_items()
|
||||
|
@@ -76,7 +76,7 @@ func Test_string_method()
|
||||
eval "a\rb\ec"->strtrans()->assert_equal('a^Mb^[c')
|
||||
eval "aあb"->strwidth()->assert_equal(4)
|
||||
eval 'abc'->substitute('b', 'x', '')->assert_equal('axc')
|
||||
call assert_fails('eval 123->items()', 'E1225:')
|
||||
call assert_fails('eval 123->items()', 'E1251: List, Tuple, Dictionary, Blob or String required for argument 1')
|
||||
|
||||
eval 'abc'->printf('the %s arg')->assert_equal('the abc arg')
|
||||
endfunc
|
||||
|
@@ -1655,7 +1655,7 @@ enddef
|
||||
|
||||
def Test_foreach()
|
||||
CheckFeature job
|
||||
v9.CheckSourceDefAndScriptFailure(['foreach(test_null_job(), "")'], ['E1013: Argument 1: type mismatch, expected list<any> but got job', 'E1251: List, Tuple, Dictionary, Blob or String required for argument 1'])
|
||||
v9.CheckSourceDefAndScriptFailure(['foreach(test_null_job(), "")'], 'E1251: List, Tuple, Dictionary, Blob or String required for argument 1')
|
||||
enddef
|
||||
|
||||
def Test_fullcommand()
|
||||
@@ -2492,15 +2492,19 @@ def Test_islocked()
|
||||
enddef
|
||||
|
||||
def Test_items()
|
||||
v9.CheckSourceDefFailure(['123->items()'], 'E1225:')
|
||||
v9.CheckSourceDefFailure(['123->items()'], 'E1251: List, Tuple, Dictionary, Blob or String required for argument 1')
|
||||
|
||||
# Dict
|
||||
assert_equal([['a', 10], ['b', 20]], {'a': 10, 'b': 20}->items())
|
||||
assert_equal([], {}->items())
|
||||
assert_equal(['x', 'x'], {'a': 10, 'b': 20}->items()->map((_, _) => 'x'))
|
||||
|
||||
# List
|
||||
assert_equal([[0, 'a'], [1, 'b']], ['a', 'b']->items())
|
||||
assert_equal([], []->items())
|
||||
assert_equal([], test_null_list()->items())
|
||||
|
||||
# String
|
||||
assert_equal([[0, 'a'], [1, '웃'], [2, 'ć']], 'a웃ć'->items())
|
||||
assert_equal([], ''->items())
|
||||
assert_equal([], test_null_string()->items())
|
||||
|
@@ -724,6 +724,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1668,
|
||||
/**/
|
||||
1667,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user