aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/typval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/typval.c')
-rw-r--r--src/nvim/eval/typval.c53
1 files changed, 37 insertions, 16 deletions
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 8fc8dcc479..4458dba27d 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -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;