mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
vim-patch:9.0.0331: cannot use items() on a string
Problem: Cannot use items() on a string.
Solution: Make items() work on a string. (closes vim/vim#11016)
3e518a8ec7
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
@@ -93,10 +93,10 @@ static const char e_string_or_number_required_for_argument_nr[]
|
||||
= N_("E1220: String or Number required for argument %d");
|
||||
static const char e_string_or_list_required_for_argument_nr[]
|
||||
= N_("E1222: String or List required for argument %d");
|
||||
static const char e_string_list_or_dict_required_for_argument_nr[]
|
||||
= N_("E1225: String, List or Dictionary required for argument %d");
|
||||
static const char e_list_or_blob_required_for_argument_nr[]
|
||||
= N_("E1226: List or Blob required for argument %d");
|
||||
static const char e_list_or_dict_required_for_argument_nr[]
|
||||
= N_("E1227: List or Dictionary required for argument %d");
|
||||
static const char e_blob_required_for_argument_nr[]
|
||||
= N_("E1238: Blob required for argument %d");
|
||||
static const char e_invalid_value_for_blob_nr[]
|
||||
@@ -813,6 +813,30 @@ static void tv_list2items(typval_T *argvars, typval_T *rettv)
|
||||
});
|
||||
}
|
||||
|
||||
/// "items(string)" function
|
||||
/// Caller must have already checked that argvars[0] is a String.
|
||||
static void tv_string2items(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
const char *p = argvars[0].vval.v_string;
|
||||
|
||||
tv_list_alloc_ret(rettv, kListLenMayKnow);
|
||||
if (p == NULL) {
|
||||
return; // null string behaves like an empty string
|
||||
}
|
||||
|
||||
for (varnumber_T idx = 0; *p != NUL; idx++) {
|
||||
int len = utfc_ptr2len(p);
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
list_T *l2 = tv_list_alloc(2);
|
||||
tv_list_append_list(rettv->vval.v_list, l2);
|
||||
tv_list_append_number(l2, idx);
|
||||
tv_list_append_string(l2, p, len);
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
|
||||
/// Extend first list with the second
|
||||
///
|
||||
/// @param[out] l1 List to extend.
|
||||
@@ -3172,7 +3196,7 @@ void tv_dict_alloc_ret(typval_T *const ret_tv)
|
||||
static void tv_dict2list(typval_T *const argvars, typval_T *const rettv, const DictListType what)
|
||||
{
|
||||
if ((what == kDict2ListItems
|
||||
? tv_check_for_list_or_dict_arg(argvars, 0)
|
||||
? tv_check_for_string_or_list_or_dict_arg(argvars, 0)
|
||||
: tv_check_for_dict_arg(argvars, 0)) == FAIL) {
|
||||
tv_list_alloc_ret(rettv, 0);
|
||||
return;
|
||||
@@ -3202,15 +3226,8 @@ static void tv_dict2list(typval_T *const argvars, typval_T *const rettv, const D
|
||||
tv_item.v_type = VAR_LIST;
|
||||
tv_item.vval.v_list = sub_l;
|
||||
tv_list_ref(sub_l);
|
||||
|
||||
tv_list_append_owned_tv(sub_l, (typval_T) {
|
||||
.v_type = VAR_STRING,
|
||||
.v_lock = VAR_UNLOCKED,
|
||||
.vval.v_string = xstrdup(di->di_key),
|
||||
});
|
||||
|
||||
tv_list_append_string(sub_l, di->di_key, -1);
|
||||
tv_list_append_tv(sub_l, &di->di_tv);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3222,7 +3239,9 @@ static void tv_dict2list(typval_T *const argvars, typval_T *const rettv, const D
|
||||
/// "items(dict)" function
|
||||
void f_items(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
||||
{
|
||||
if (argvars[0].v_type == VAR_LIST) {
|
||||
if (argvars[0].v_type == VAR_STRING) {
|
||||
tv_string2items(argvars, rettv);
|
||||
} else if (argvars[0].v_type == VAR_LIST) {
|
||||
tv_list2items(argvars, rettv);
|
||||
} else {
|
||||
tv_dict2list(argvars, rettv, kDict2ListItems);
|
||||
@@ -4436,12 +4455,14 @@ int tv_check_for_opt_string_or_list_arg(const typval_T *const args, const int id
|
||||
|| tv_check_for_string_or_list_arg(args, idx) != FAIL) ? OK : FAIL;
|
||||
}
|
||||
|
||||
/// Give an error and return FAIL unless "args[idx]" is a list or dict
|
||||
int tv_check_for_list_or_dict_arg(const typval_T *const args, const int idx)
|
||||
/// Give an error and return FAIL unless "args[idx]" is a string or a list or a dict
|
||||
int tv_check_for_string_or_list_or_dict_arg(const typval_T *const args, const int idx)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
|
||||
{
|
||||
if (args[idx].v_type != VAR_LIST && args[idx].v_type != VAR_DICT) {
|
||||
semsg(_(e_list_or_dict_required_for_argument_nr), idx + 1);
|
||||
if (args[idx].v_type != VAR_STRING
|
||||
&& args[idx].v_type != VAR_LIST
|
||||
&& args[idx].v_type != VAR_DICT) {
|
||||
semsg(_(e_string_list_or_dict_required_for_argument_nr), idx + 1);
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
|
@@ -203,7 +203,16 @@ func Test_list_items()
|
||||
endfor
|
||||
call assert_equal([[0, 'a'], [1, 'b'], [2, 'c']], r)
|
||||
|
||||
call assert_fails('call items(3)', 'E1227:')
|
||||
call assert_fails('call items(3)', 'E1225:')
|
||||
endfunc
|
||||
|
||||
func Test_string_items()
|
||||
let r = []
|
||||
let s = 'ábツ'
|
||||
for [idx, val] in items(s)
|
||||
call extend(r, [[idx, val]])
|
||||
endfor
|
||||
call assert_equal([[0, 'á'], [1, 'b'], [2, 'ツ']], r)
|
||||
endfunc
|
||||
|
||||
" Test removing items in list
|
||||
|
Reference in New Issue
Block a user