diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-07-30 11:34:38 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2024-07-30 12:18:44 +0800 |
commit | 8ca3c1515c3fd5f70e870e535649a4c2afc5bbaf (patch) | |
tree | b1a04b07fc123ffb82b9fc98a50f4ffac05ba25d | |
parent | 2dd0a90f211268517af30607c8eade0fef533edb (diff) | |
download | rneovim-8ca3c1515c3fd5f70e870e535649a4c2afc5bbaf.tar.gz rneovim-8ca3c1515c3fd5f70e870e535649a4c2afc5bbaf.tar.bz2 rneovim-8ca3c1515c3fd5f70e870e535649a4c2afc5bbaf.zip |
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)
https://github.com/vim/vim/commit/3e518a8ec74065aedd67d352c93d6ae6be550316
Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r-- | src/nvim/eval/typval.c | 53 | ||||
-rw-r--r-- | test/old/testdir/test_listdict.vim | 11 |
2 files changed, 47 insertions, 17 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; diff --git a/test/old/testdir/test_listdict.vim b/test/old/testdir/test_listdict.vim index e976dc4c29..5e4a3fd1f8 100644 --- a/test/old/testdir/test_listdict.vim +++ b/test/old/testdir/test_listdict.vim @@ -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 |