To: vim_dev@googlegroups.com Subject: Patch 8.2.1698 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1698 Problem: Cannot lock a variable in legacy Vim script like in Vim9. Solution: Make ":lockvar 0" work. Files: runtime/doc/eval.txt, src/evalvars.c, src/proto/evalvars.pro, src/dict.c, src/eval.c, src/list.c, src/typval.c, src/userfunc.c, src/testdir/test_const.vim, src/testdir/test_listdict.vim *** ../vim-8.2.1697/runtime/doc/eval.txt 2020-09-11 22:25:11.298775020 +0200 --- runtime/doc/eval.txt 2020-09-16 19:21:34.226886459 +0200 *************** *** 12295,12301 **** < is equivalent to: > :let x = 1 :lockvar! x ! < This is useful if you want to make sure the variable is not modified. If the value is a List or Dictionary literal then the items also cannot be changed: > const ll = [1, 2, 3] --- 12366,12374 ---- < is equivalent to: > :let x = 1 :lockvar! x ! < NOTE: in Vim9 script `:const` works differently, see ! |vim9-const| ! This is useful if you want to make sure the variable is not modified. If the value is a List or Dictionary literal then the items also cannot be changed: > const ll = [1, 2, 3] *************** *** 12335,12340 **** --- 12408,12415 ---- [depth] is relevant when locking a |List| or |Dictionary|. It specifies how deep the locking goes: + 0 Lock the variable {name} but not its + value. 1 Lock the |List| or |Dictionary| itself, cannot add or remove items, but can still change their values. *************** *** 12348,12354 **** |Dictionary|, one level deeper. The default [depth] is 2, thus when {name} is a |List| or |Dictionary| the values cannot be changed. ! *E743* For unlimited depth use [!] and omit [depth]. However, there is a maximum depth of 100 to catch loops. --- 12423,12436 ---- |Dictionary|, one level deeper. The default [depth] is 2, thus when {name} is a |List| or |Dictionary| the values cannot be changed. ! ! Example with [depth] 0: > ! let mylist = [1, 2, 3] ! lockvar 0 mylist ! let mylist[0] = 77 " OK ! call add(mylist, 4] " OK ! let mylist = [7, 8, 9] " Error! ! < *E743* For unlimited depth use [!] and omit [depth]. However, there is a maximum depth of 100 to catch loops. *** ../vim-8.2.1697/src/evalvars.c 2020-09-14 21:38:47.756976285 +0200 --- src/evalvars.c 2020-09-16 20:45:20.947252995 +0200 *************** *** 1560,1568 **** *name_end = cc; } else if ((lp->ll_list != NULL ! && var_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE)) || (lp->ll_dict != NULL ! && var_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE))) return FAIL; else if (lp->ll_range) { --- 1560,1568 ---- *name_end = cc; } else if ((lp->ll_list != NULL ! && value_check_lock(lp->ll_list->lv_lock, lp->ll_name, FALSE)) || (lp->ll_dict != NULL ! && value_check_lock(lp->ll_dict->dv_lock, lp->ll_name, FALSE))) return FAIL; else if (lp->ll_range) { *************** *** 1573,1579 **** while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1)) { li = ll_li->li_next; ! if (var_check_lock(ll_li->li_tv.v_lock, lp->ll_name, FALSE)) return FAIL; ll_li = li; ++ll_n1; --- 1573,1579 ---- while (ll_li != NULL && (lp->ll_empty2 || lp->ll_n2 >= ll_n1)) { li = ll_li->li_next; ! if (value_check_lock(ll_li->li_tv.v_lock, lp->ll_name, FALSE)) return FAIL; ll_li = li; ++ll_n1; *************** *** 1646,1652 **** di = HI2DI(hi); if (var_check_fixed(di->di_flags, name, FALSE) || var_check_ro(di->di_flags, name, FALSE) ! || var_check_lock(d->dv_lock, name, FALSE)) return FAIL; delete_var(ht, hi); --- 1646,1652 ---- di = HI2DI(hi); if (var_check_fixed(di->di_flags, name, FALSE) || var_check_ro(di->di_flags, name, FALSE) ! || value_check_lock(d->dv_lock, name, FALSE)) return FAIL; delete_var(ht, hi); *************** *** 1677,1685 **** int cc; dictitem_T *di; - if (deep == 0) // nothing to do - return OK; - if (lp->ll_tv == NULL) { cc = *name_end; --- 1677,1682 ---- *************** *** 1710,1720 **** di->di_flags |= DI_FLAGS_LOCK; else di->di_flags &= ~DI_FLAGS_LOCK; ! item_lock(&di->di_tv, deep, lock, FALSE); } } *name_end = cc; } else if (lp->ll_range) { listitem_T *li = lp->ll_li; --- 1707,1722 ---- di->di_flags |= DI_FLAGS_LOCK; else di->di_flags &= ~DI_FLAGS_LOCK; ! if (deep != 0) ! item_lock(&di->di_tv, deep, lock, FALSE); } } *name_end = cc; } + else if (deep == 0) + { + // nothing to do + } else if (lp->ll_range) { listitem_T *li = lp->ll_li; *************** *** 3007,3014 **** goto failed; } if (var_check_ro(di->di_flags, name, FALSE) ! || var_check_lock(di->di_tv.v_lock, name, FALSE)) goto failed; } else --- 3009,3021 ---- goto failed; } + // Check in this order for backwards compatibility: + // - Whether the variable is read-only + // - Whether the variable value is locked + // - Whether the variable is locked if (var_check_ro(di->di_flags, name, FALSE) ! || value_check_lock(di->di_tv.v_lock, name, FALSE) ! || var_check_lock(di->di_flags, name, FALSE)) goto failed; } else *************** *** 3158,3163 **** --- 3165,3186 ---- } /* + * Return TRUE if di_flags "flags" indicates variable "name" is locked. + * Also give an error message. + */ + int + var_check_lock(int flags, char_u *name, int use_gettext) + { + if (flags & DI_FLAGS_LOCK) + { + semsg(_(e_variable_is_locked_str), + use_gettext ? (char_u *)_(name) : name); + return TRUE; + } + return FALSE; + } + + /* * Return TRUE if di_flags "flags" indicates variable "name" is fixed. * Also give an error message. */ *************** *** 3204,3215 **** } /* ! * Return TRUE if "flags" indicates variable "name" is locked (immutable). ! * Also give an error message, using "name" or _("name") when use_gettext is ! * TRUE. */ int ! var_check_lock(int lock, char_u *name, int use_gettext) { if (lock & VAR_LOCKED) { --- 3227,3238 ---- } /* ! * Return TRUE if "flags" indicates variable "name" has a locked (immutable) ! * value. Also give an error message, using "name" or _("name") when ! * "use_gettext" is TRUE. */ int ! value_check_lock(int lock, char_u *name, int use_gettext) { if (lock & VAR_LOCKED) { *** ../vim-8.2.1697/src/proto/evalvars.pro 2020-09-14 21:38:47.756976285 +0200 --- src/proto/evalvars.pro 2020-09-16 20:10:04.108635041 +0200 *************** *** 68,76 **** void set_var(char_u *name, typval_T *tv, int copy); void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy, int flags); int var_check_ro(int flags, char_u *name, int use_gettext); int var_check_fixed(int flags, char_u *name, int use_gettext); int var_wrong_func_name(char_u *name, int new_var); ! int var_check_lock(int lock, char_u *name, int use_gettext); int valid_varname(char_u *varname); void reset_v_option_vars(void); void assert_error(garray_T *gap); --- 68,77 ---- void set_var(char_u *name, typval_T *tv, int copy); void set_var_const(char_u *name, type_T *type, typval_T *tv_arg, int copy, int flags); int var_check_ro(int flags, char_u *name, int use_gettext); + int var_check_lock(int flags, char_u *name, int use_gettext); int var_check_fixed(int flags, char_u *name, int use_gettext); int var_wrong_func_name(char_u *name, int new_var); ! int value_check_lock(int lock, char_u *name, int use_gettext); int valid_varname(char_u *varname); void reset_v_option_vars(void); void assert_error(garray_T *gap); *** ../vim-8.2.1697/src/dict.c 2020-08-21 22:36:43.662719906 +0200 --- src/dict.c 2020-09-16 20:07:32.249025849 +0200 *************** *** 1009,1015 **** } else if (*action == 'f' && HI2DI(hi2) != di1) { ! if (var_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE) || var_check_ro(di1->di_flags, arg_errmsg, TRUE)) break; clear_tv(&di1->di_tv); --- 1009,1015 ---- } else if (*action == 'f' && HI2DI(hi2) != di1) { ! if (value_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE) || var_check_ro(di1->di_flags, arg_errmsg, TRUE)) break; clear_tv(&di1->di_tv); *************** *** 1227,1233 **** if (argvars[2].v_type != VAR_UNKNOWN) semsg(_(e_toomanyarg), "remove()"); else if ((d = argvars[0].vval.v_dict) != NULL ! && !var_check_lock(d->dv_lock, arg_errmsg, TRUE)) { key = tv_get_string_chk(&argvars[1]); if (key != NULL) --- 1227,1233 ---- if (argvars[2].v_type != VAR_UNKNOWN) semsg(_(e_toomanyarg), "remove()"); else if ((d = argvars[0].vval.v_dict) != NULL ! && !value_check_lock(d->dv_lock, arg_errmsg, TRUE)) { key = tv_get_string_chk(&argvars[1]); if (key != NULL) *** ../vim-8.2.1697/src/eval.c 2020-09-14 21:38:47.760976275 +0200 --- src/eval.c 2020-09-16 20:09:14.860767539 +0200 *************** *** 1055,1061 **** } // existing variable, need to check if it can be changed else if ((flags & GLV_READ_ONLY) == 0 ! && var_check_ro(lp->ll_di->di_flags, name, FALSE)) { clear_tv(&var1); return NULL; --- 1055,1062 ---- } // existing variable, need to check if it can be changed else if ((flags & GLV_READ_ONLY) == 0 ! && (var_check_ro(lp->ll_di->di_flags, name, FALSE) ! || var_check_lock(lp->ll_di->di_flags, name, FALSE))) { clear_tv(&var1); return NULL; *************** *** 1220,1226 **** semsg(_(e_letwrong), op); return; } ! if (var_check_lock(lp->ll_blob->bv_lock, lp->ll_name, FALSE)) return; if (lp->ll_range && rettv->v_type == VAR_BLOB) --- 1221,1227 ---- semsg(_(e_letwrong), op); return; } ! if (value_check_lock(lp->ll_blob->bv_lock, lp->ll_name, FALSE)) return; if (lp->ll_range && rettv->v_type == VAR_BLOB) *************** *** 1297,1303 **** } *endp = cc; } ! else if (var_check_lock(lp->ll_newkey == NULL ? lp->ll_tv->v_lock : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name, FALSE)) ; --- 1298,1304 ---- } *endp = cc; } ! else if (value_check_lock(lp->ll_newkey == NULL ? lp->ll_tv->v_lock : lp->ll_tv->vval.v_dict->dv_lock, lp->ll_name, FALSE)) ; *************** *** 1317,1323 **** */ for (ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; ) { ! if (var_check_lock(ll_li->li_tv.v_lock, lp->ll_name, FALSE)) return; ri = ri->li_next; if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == ll_n1)) --- 1318,1324 ---- */ for (ri = rettv->vval.v_list->lv_first; ri != NULL && ll_li != NULL; ) { ! if (value_check_lock(ll_li->li_tv.v_lock, lp->ll_name, FALSE)) return; ri = ri->li_next; if (ri == NULL || (!lp->ll_empty2 && lp->ll_n2 == ll_n1)) *** ../vim-8.2.1697/src/list.c 2020-09-05 20:16:54.330410797 +0200 --- src/list.c 2020-09-16 19:57:24.737714059 +0200 *************** *** 817,823 **** } l = argvars[0].vval.v_list; ! if (l != NULL && !var_check_lock(l->lv_lock, (char_u *)N_("flatten() argument"), TRUE) && list_flatten(l, maxdepth) == OK) copy_tv(&argvars[0], rettv); --- 817,823 ---- } l = argvars[0].vval.v_list; ! if (l != NULL && !value_check_lock(l->lv_lock, (char_u *)N_("flatten() argument"), TRUE) && list_flatten(l, maxdepth) == OK) copy_tv(&argvars[0], rettv); *************** *** 1439,1445 **** int idx; if ((l = argvars[0].vval.v_list) == NULL ! || var_check_lock(l->lv_lock, arg_errmsg, TRUE)) return; idx = (long)tv_get_number_chk(&argvars[1], &error); --- 1439,1445 ---- int idx; if ((l = argvars[0].vval.v_list) == NULL ! || value_check_lock(l->lv_lock, arg_errmsg, TRUE)) return; idx = (long)tv_get_number_chk(&argvars[1], &error); *************** *** 1687,1693 **** else { l = argvars[0].vval.v_list; ! if (l == NULL || var_check_lock(l->lv_lock, (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), TRUE)) goto theend; --- 1687,1693 ---- else { l = argvars[0].vval.v_list; ! if (l == NULL || value_check_lock(l->lv_lock, (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")), TRUE)) goto theend; *************** *** 1955,1967 **** else if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL ! || (!map && var_check_lock(l->lv_lock, arg_errmsg, TRUE))) return; } else if (argvars[0].v_type == VAR_DICT) { if ((d = argvars[0].vval.v_dict) == NULL ! || (!map && var_check_lock(d->dv_lock, arg_errmsg, TRUE))) return; } else --- 1955,1967 ---- else if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) == NULL ! || (!map && value_check_lock(l->lv_lock, arg_errmsg, TRUE))) return; } else if (argvars[0].v_type == VAR_DICT) { if ((d = argvars[0].vval.v_dict) == NULL ! || (!map && value_check_lock(d->dv_lock, arg_errmsg, TRUE))) return; } else *************** *** 2004,2010 **** --todo; di = HI2DI(hi); ! if (map && (var_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE) || var_check_ro(di->di_flags, arg_errmsg, TRUE))) --- 2004,2010 ---- --todo; di = HI2DI(hi); ! if (map && (value_check_lock(di->di_tv.v_lock, arg_errmsg, TRUE) || var_check_ro(di->di_flags, arg_errmsg, TRUE))) *************** *** 2077,2083 **** l->lv_lock = VAR_LOCKED; for (li = l->lv_first; li != NULL; li = nli) { ! if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) break; nli = li->li_next; set_vim_var_nr(VV_KEY, idx); --- 2077,2083 ---- l->lv_lock = VAR_LOCKED; for (li = l->lv_first; li != NULL; li = nli) { ! if (map && value_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE)) break; nli = li->li_next; set_vim_var_nr(VV_KEY, idx); *************** *** 2131,2137 **** if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) != NULL ! && !var_check_lock(l->lv_lock, (char_u *)N_("add() argument"), TRUE) && list_append_tv(l, &argvars[1]) == OK) copy_tv(&argvars[0], rettv); --- 2131,2137 ---- if (argvars[0].v_type == VAR_LIST) { if ((l = argvars[0].vval.v_list) != NULL ! && !value_check_lock(l->lv_lock, (char_u *)N_("add() argument"), TRUE) && list_append_tv(l, &argvars[1]) == OK) copy_tv(&argvars[0], rettv); *************** *** 2139,2145 **** else if (argvars[0].v_type == VAR_BLOB) { if ((b = argvars[0].vval.v_blob) != NULL ! && !var_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE)) { int error = FALSE; --- 2139,2145 ---- else if (argvars[0].v_type == VAR_BLOB) { if ((b = argvars[0].vval.v_blob) != NULL ! && !value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE)) { int error = FALSE; *************** *** 2282,2288 **** l1 = argvars[0].vval.v_list; l2 = argvars[1].vval.v_list; ! if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE) && l2 != NULL) { if (argvars[2].v_type != VAR_UNKNOWN) --- 2282,2288 ---- l1 = argvars[0].vval.v_list; l2 = argvars[1].vval.v_list; ! if (l1 != NULL && !value_check_lock(l1->lv_lock, arg_errmsg, TRUE) && l2 != NULL) { if (argvars[2].v_type != VAR_UNKNOWN) *************** *** 2318,2324 **** d1 = argvars[0].vval.v_dict; d2 = argvars[1].vval.v_dict; ! if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE) && d2 != NULL) { // Check the third argument. --- 2318,2324 ---- d1 = argvars[0].vval.v_dict; d2 = argvars[1].vval.v_dict; ! if (d1 != NULL && !value_check_lock(d1->dv_lock, arg_errmsg, TRUE) && d2 != NULL) { // Check the third argument. *************** *** 2402,2408 **** else if (argvars[0].v_type != VAR_LIST) semsg(_(e_listblobarg), "insert()"); else if ((l = argvars[0].vval.v_list) != NULL ! && !var_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE)) { if (argvars[2].v_type != VAR_UNKNOWN) --- 2402,2408 ---- else if (argvars[0].v_type != VAR_LIST) semsg(_(e_listblobarg), "insert()"); else if ((l = argvars[0].vval.v_list) != NULL ! && !value_check_lock(l->lv_lock, (char_u *)N_("insert() argument"), TRUE)) { if (argvars[2].v_type != VAR_UNKNOWN) *************** *** 2475,2481 **** if (argvars[0].v_type != VAR_LIST) semsg(_(e_listblobarg), "reverse()"); else if ((l = argvars[0].vval.v_list) != NULL ! && !var_check_lock(l->lv_lock, (char_u *)N_("reverse() argument"), TRUE)) { if (l->lv_first == &range_list_item) --- 2475,2481 ---- if (argvars[0].v_type != VAR_LIST) semsg(_(e_listblobarg), "reverse()"); else if ((l = argvars[0].vval.v_list) != NULL ! && !value_check_lock(l->lv_lock, (char_u *)N_("reverse() argument"), TRUE)) { if (l->lv_first == &range_list_item) *** ../vim-8.2.1697/src/typval.c 2020-09-02 21:30:04.667134268 +0200 --- src/typval.c 2020-09-16 19:55:49.381602348 +0200 *************** *** 512,519 **** default: break; } ! return var_check_lock(tv->v_lock, name, use_gettext) ! || (lock != 0 && var_check_lock(lock, name, use_gettext)); } /* --- 512,519 ---- default: break; } ! return value_check_lock(tv->v_lock, name, use_gettext) ! || (lock != 0 && value_check_lock(lock, name, use_gettext)); } /* *** ../vim-8.2.1697/src/userfunc.c 2020-09-14 16:37:30.906845912 +0200 --- src/userfunc.c 2020-09-16 19:56:07.413630310 +0200 *************** *** 3346,3356 **** if (fudi.fd_di == NULL) { // Can't add a function to a locked dictionary ! if (var_check_lock(fudi.fd_dict->dv_lock, eap->arg, FALSE)) goto erret; } // Can't change an existing function if it is locked ! else if (var_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, FALSE)) goto erret; // Give the function a sequential number. Can only be used with a --- 3346,3356 ---- if (fudi.fd_di == NULL) { // Can't add a function to a locked dictionary ! if (value_check_lock(fudi.fd_dict->dv_lock, eap->arg, FALSE)) goto erret; } // Can't change an existing function if it is locked ! else if (value_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg, FALSE)) goto erret; // Give the function a sequential number. Can only be used with a *** ../vim-8.2.1697/src/testdir/test_const.vim 2020-09-04 21:18:40.480161935 +0200 --- src/testdir/test_const.vim 2020-09-16 20:00:34.741711844 +0200 *************** *** 215,220 **** --- 215,228 ---- if 0 | lockvar x | endif let x = 'again' + + let val = [1, 2, 3] + lockvar 0 val + let val[0] = 9 + call assert_equal([9, 2, 3], val) + call add(val, 4) + call assert_equal([9, 2, 3, 4], val) + call assert_fails('let val = [4, 5, 6]', 'E1122:') endfunc *** ../vim-8.2.1697/src/testdir/test_listdict.vim 2020-09-05 17:18:22.501432257 +0200 --- src/testdir/test_listdict.vim 2020-09-16 20:51:40.918185849 +0200 *************** *** 354,360 **** " Locked variables func Test_list_locked_var() let expected = [ ! \ [['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp']], \ [['1000-000', 'ppppppF'], --- 354,360 ---- " Locked variables func Test_list_locked_var() let expected = [ ! \ [['1000-000', 'ppppppF'], \ ['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp']], \ [['1000-000', 'ppppppF'], *************** *** 381,387 **** exe "unlockvar " . depth . " l" endif let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") ! call assert_equal(expected[depth][u][0], ps) let ps = '' try let l[1][1][0] = 99 --- 381,387 ---- exe "unlockvar " . depth . " l" endif let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") ! call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth) let ps = '' try let l[1][1][0] = 99 *************** *** 425,431 **** catch let ps .= 'F' endtry ! call assert_equal(expected[depth][u][1], ps) endfor endfor call assert_fails("let x=islocked('a b')", 'E488:') --- 425,431 ---- catch let ps .= 'F' endtry ! call assert_equal(expected[depth][u][1], ps, 'depth: ' .. depth) endfor endfor call assert_fails("let x=islocked('a b')", 'E488:') *************** *** 438,444 **** " Unletting locked variables func Test_list_locked_var_unlet() let expected = [ ! \ [['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp']], \ [['1000-000', 'ppFppFp'], --- 438,444 ---- " Unletting locked variables func Test_list_locked_var_unlet() let expected = [ ! \ [['1000-000', 'ppppppp'], \ ['0000-000', 'ppppppp'], \ ['0000-000', 'ppppppp']], \ [['1000-000', 'ppFppFp'], *************** *** 466,472 **** exe "unlockvar " . depth . " l" endif let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") ! call assert_equal(expected[depth][u][0], ps) let ps = '' try unlet l[2]['6'][7] --- 466,472 ---- exe "unlockvar " . depth . " l" endif let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]") ! call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth) let ps = '' try unlet l[2]['6'][7] *************** *** 666,671 **** --- 666,674 ---- call s:arg_list_test(1, 2, [3, 4], {5: 6}) endfunc + func Test_dict_item_locked() + endfunc + " Tests for reverse(), sort(), uniq() func Test_reverse_sort_uniq() let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5] *** ../vim-8.2.1697/src/version.c 2020-09-16 17:55:36.537602345 +0200 --- src/version.c 2020-09-16 21:07:07.666732357 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 1698, /**/ -- (letter from Mark to Mike, about the film's probable certificate) I would like to get back to the Censor and agree to lose the shits, take the odd Jesus Christ out and lose Oh fuck off, but to retain 'fart in your general direction', 'castanets of your testicles' and 'oral sex' and ask him for an 'A' rating on that basis. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///