aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-06-12 15:38:53 +0800
committerzeertzjq <zeertzjq@outlook.com>2023-06-12 17:20:55 +0800
commita0cb53eca7a04326dd857cf33fac1154aff7773a (patch)
tree73d0046d0cd7752b0503e60b5c55cd1f0b512bbc
parent551cc3a2a3e2ee180234910cbe2ef81bd37508de (diff)
downloadrneovim-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.c8
-rw-r--r--src/nvim/eval/typval.c15
-rw-r--r--src/nvim/eval/vars.c46
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.