diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-06-12 15:38:53 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2023-06-12 17:20:55 +0800 |
commit | a0cb53eca7a04326dd857cf33fac1154aff7773a (patch) | |
tree | 73d0046d0cd7752b0503e60b5c55cd1f0b512bbc | |
parent | 551cc3a2a3e2ee180234910cbe2ef81bd37508de (diff) | |
download | rneovim-a0cb53eca7a04326dd857cf33fac1154aff7773a.tar.gz rneovim-a0cb53eca7a04326dd857cf33fac1154aff7773a.tar.bz2 rneovim-a0cb53eca7a04326dd857cf33fac1154aff7773a.zip |
vim-patch:8.2.2533: Vim9: cannot use a range with :unlet
Problem: Vim9: cannot use a range with :unlet.
Solution: Implement ISN_UNLETRANGE.
https://github.com/vim/vim/commit/5b5ae29bd3d7b832b6f15320430f7f191e0abd1f
Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r-- | src/nvim/eval.c | 8 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 15 | ||||
-rw-r--r-- | src/nvim/eval/vars.c | 46 |
3 files changed, 44 insertions, 25 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ec5437a0b2..50da0a8657 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1604,13 +1604,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const lp->ll_dict = NULL; lp->ll_list = lp->ll_tv->vval.v_list; - lp->ll_li = tv_list_find(lp->ll_list, (int)lp->ll_n1); - if (lp->ll_li == NULL) { - if (lp->ll_n1 < 0) { - lp->ll_n1 = 0; - lp->ll_li = tv_list_find(lp->ll_list, (int)lp->ll_n1); - } - } + lp->ll_li = tv_list_find_index(lp->ll_list, &lp->ll_n1); if (lp->ll_li == NULL) { tv_clear(&var2); if (!quiet) { diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index a392d441cf..9e697d6144 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -1507,6 +1507,21 @@ const char *tv_list_find_str(list_T *const l, const int n) return tv_get_string(TV_LIST_ITEM_TV(li)); } +/// Like tv_list_find() but when a negative index is used that is not found use +/// zero and set "idx" to zero. Used for first index of a range. +listitem_T *tv_list_find_index(list_T *const l, long *const idx) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + listitem_T *li = tv_list_find(l, (int)(*idx)); + if (li == NULL) { + if (*idx < 0) { + *idx = 0; + li = tv_list_find(l, (int)(*idx)); + } + } + return li; +} + /// Locate item in a list and return its index /// /// @param[in] l List to search. diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 0663c3c54c..f988a49e6c 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -1056,25 +1056,10 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ lp->ll_name_len))) { return FAIL; } else if (lp->ll_range) { - assert(lp->ll_list != NULL); - // Delete a range of List items. - listitem_T *const first_li = lp->ll_li; - listitem_T *last_li = first_li; - while (true) { - listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li); - if (value_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock, - lp->ll_name, - lp->ll_name_len)) { - return false; - } - lp->ll_li = li; - lp->ll_n1++; - if (lp->ll_li == NULL || (!lp->ll_empty2 && lp->ll_n2 < lp->ll_n1)) { - break; - } - last_li = lp->ll_li; + if (list_unlet_range(lp->ll_list, lp->ll_li, lp->ll_name, lp->ll_name_len, + lp->ll_n1, !lp->ll_empty2, lp->ll_n2) == FAIL) { + return FAIL; } - tv_list_remove_items(lp->ll_list, first_li, last_li); } else { if (lp->ll_list != NULL) { // unlet a List item. @@ -1107,6 +1092,31 @@ static int do_unlet_var(lval_T *lp, char *name_end, exarg_T *eap, int deep FUNC_ return ret; } +/// Unlet one item or a range of items from a list. +/// Return OK or FAIL. +static int list_unlet_range(list_T *const l, listitem_T *const li_first, const char *const name, + const size_t name_len, const long n1_arg, const bool has_n2, + const long n2) +{ + assert(l != NULL); + // Delete a range of List items. + listitem_T *li_last = li_first; + long n1 = n1_arg; + while (true) { + if (value_check_lock(TV_LIST_ITEM_TV(li_last)->v_lock, name, name_len)) { + return FAIL; + } + listitem_T *const li = TV_LIST_ITEM_NEXT(l, li_last); + n1++; + if (li == NULL || (has_n2 && n2 < n1)) { + break; + } + li_last = li; + } + tv_list_remove_items(l, li_first, li_last); + return OK; +} + /// unlet a variable /// /// @param[in] name Variable name to unlet. |