mirror of
https://github.com/neovim/neovim.git
synced 2025-09-28 05:58:33 +00:00
eval: Refactor item_lock
If I am not mistaking, this commit should not change any functionality.
This commit is contained in:
@@ -3112,68 +3112,71 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock)
|
|||||||
static void item_lock(typval_T *tv, int deep, int lock)
|
static void item_lock(typval_T *tv, int deep, int lock)
|
||||||
{
|
{
|
||||||
static int recurse = 0;
|
static int recurse = 0;
|
||||||
list_T *l;
|
|
||||||
listitem_T *li;
|
|
||||||
dict_T *d;
|
|
||||||
hashitem_T *hi;
|
|
||||||
int todo;
|
|
||||||
|
|
||||||
if (recurse >= DICT_MAXNEST) {
|
if (recurse >= DICT_MAXNEST) {
|
||||||
EMSG(_("E743: variable nested too deep for (un)lock"));
|
EMSG(_("E743: variable nested too deep for (un)lock"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (deep == 0)
|
if (deep == 0) {
|
||||||
return;
|
return;
|
||||||
++recurse;
|
}
|
||||||
|
recurse++;
|
||||||
|
|
||||||
/* lock/unlock the item itself */
|
// lock/unlock the item itself
|
||||||
if (lock)
|
#define CHANGE_LOCK(var, lock) \
|
||||||
tv->v_lock |= VAR_LOCKED;
|
do { \
|
||||||
else
|
var = ((VarLockStatus[]) { \
|
||||||
tv->v_lock &= ~VAR_LOCKED;
|
[VAR_UNLOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
|
||||||
|
[VAR_LOCKED] = (lock ? VAR_LOCKED : VAR_UNLOCKED), \
|
||||||
|
[VAR_FIXED] = VAR_FIXED, \
|
||||||
|
})[var]; \
|
||||||
|
} while (0)
|
||||||
|
CHANGE_LOCK(tv->v_lock, lock);
|
||||||
|
|
||||||
switch (tv->v_type) {
|
switch (tv->v_type) {
|
||||||
case VAR_LIST:
|
case VAR_LIST: {
|
||||||
if ((l = tv->vval.v_list) != NULL) {
|
list_T *const l = tv->vval.v_list;
|
||||||
if (lock)
|
if (l != NULL) {
|
||||||
l->lv_lock |= VAR_LOCKED;
|
CHANGE_LOCK(l->lv_lock, lock);
|
||||||
else
|
|
||||||
l->lv_lock &= ~VAR_LOCKED;
|
|
||||||
if (deep < 0 || deep > 1)
|
if (deep < 0 || deep > 1)
|
||||||
/* recursive: lock/unlock the items the List contains */
|
// Recursive: lock/unlock the items the List contains.
|
||||||
for (li = l->lv_first; li != NULL; li = li->li_next)
|
for (listitem_T *li = l->lv_first; li != NULL; li = li->li_next) {
|
||||||
item_lock(&li->li_tv, deep - 1, lock);
|
item_lock(&li->li_tv, deep - 1, lock);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case VAR_DICT:
|
}
|
||||||
if ((d = tv->vval.v_dict) != NULL) {
|
case VAR_DICT: {
|
||||||
if (lock)
|
dict_T *const d = tv->vval.v_dict;
|
||||||
d->dv_lock |= VAR_LOCKED;
|
if (d != NULL) {
|
||||||
else
|
CHANGE_LOCK(d->dv_lock, lock);
|
||||||
d->dv_lock &= ~VAR_LOCKED;
|
|
||||||
if (deep < 0 || deep > 1) {
|
if (deep < 0 || deep > 1) {
|
||||||
/* recursive: lock/unlock the items the List contains */
|
// Recursive: lock/unlock the items the List contains.
|
||||||
todo = (int)d->dv_hashtab.ht_used;
|
int todo = (int)d->dv_hashtab.ht_used;
|
||||||
for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) {
|
for (hashitem_T *hi = d->dv_hashtab.ht_array; todo > 0; hi++) {
|
||||||
if (!HASHITEM_EMPTY(hi)) {
|
if (!HASHITEM_EMPTY(hi)) {
|
||||||
--todo;
|
todo--;
|
||||||
item_lock(&HI2DI(hi)->di_tv, deep - 1, lock);
|
item_lock(&HI2DI(hi)->di_tv, deep - 1, lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case VAR_NUMBER:
|
case VAR_NUMBER:
|
||||||
case VAR_FLOAT:
|
case VAR_FLOAT:
|
||||||
case VAR_STRING:
|
case VAR_STRING:
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
case VAR_PARTIAL:
|
case VAR_PARTIAL:
|
||||||
case VAR_SPECIAL:
|
case VAR_SPECIAL: {
|
||||||
break;
|
break;
|
||||||
case VAR_UNKNOWN:
|
}
|
||||||
|
case VAR_UNKNOWN: {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
--recurse;
|
}
|
||||||
|
#undef CHANGE_LOCK
|
||||||
|
recurse--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -6350,7 +6353,7 @@ dict_T *dict_alloc(void) FUNC_ATTR_NONNULL_RET
|
|||||||
first_dict = d;
|
first_dict = d;
|
||||||
|
|
||||||
hash_init(&d->dv_hashtab);
|
hash_init(&d->dv_hashtab);
|
||||||
d->dv_lock = 0;
|
d->dv_lock = VAR_UNLOCKED;
|
||||||
d->dv_scope = 0;
|
d->dv_scope = 0;
|
||||||
d->dv_refcount = 0;
|
d->dv_refcount = 0;
|
||||||
d->dv_copyID = 0;
|
d->dv_copyID = 0;
|
||||||
@@ -20293,7 +20296,7 @@ void new_script_vars(scid_T id)
|
|||||||
void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
|
void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
|
||||||
{
|
{
|
||||||
hash_init(&dict->dv_hashtab);
|
hash_init(&dict->dv_hashtab);
|
||||||
dict->dv_lock = 0;
|
dict->dv_lock = VAR_UNLOCKED;
|
||||||
dict->dv_scope = scope;
|
dict->dv_scope = scope;
|
||||||
dict->dv_refcount = DO_NOT_FREE_CNT;
|
dict->dv_refcount = DO_NOT_FREE_CNT;
|
||||||
dict->dv_copyID = 0;
|
dict->dv_copyID = 0;
|
||||||
|
@@ -30,8 +30,8 @@ typedef enum {
|
|||||||
/// Variable lock status for typval_T.v_lock
|
/// Variable lock status for typval_T.v_lock
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VAR_UNLOCKED = 0, ///< Not locked.
|
VAR_UNLOCKED = 0, ///< Not locked.
|
||||||
VAR_LOCKED, ///< User lock, can be unlocked.
|
VAR_LOCKED = 1, ///< User lock, can be unlocked.
|
||||||
VAR_FIXED, ///< Locked forever.
|
VAR_FIXED = 2, ///< Locked forever.
|
||||||
} VarLockStatus;
|
} VarLockStatus;
|
||||||
|
|
||||||
/// VimL variable types, for use in typval_T.v_type
|
/// VimL variable types, for use in typval_T.v_type
|
||||||
@@ -93,18 +93,18 @@ struct listwatch_S {
|
|||||||
* Structure to hold info about a list.
|
* Structure to hold info about a list.
|
||||||
*/
|
*/
|
||||||
struct listvar_S {
|
struct listvar_S {
|
||||||
listitem_T *lv_first; /* first item, NULL if none */
|
listitem_T *lv_first; ///< First item, NULL if none.
|
||||||
listitem_T *lv_last; /* last item, NULL if none */
|
listitem_T *lv_last; ///< Last item, NULL if none.
|
||||||
int lv_refcount; /* reference count */
|
int lv_refcount; ///< Reference count.
|
||||||
int lv_len; /* number of items */
|
int lv_len; ///< Number of items.
|
||||||
listwatch_T *lv_watch; /* first watcher, NULL if none */
|
listwatch_T *lv_watch; ///< First watcher, NULL if none.
|
||||||
int lv_idx; /* cached index of an item */
|
int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
|
||||||
listitem_T *lv_idx_item; /* when not NULL item at index "lv_idx" */
|
listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
|
||||||
int lv_copyID; /* ID used by deepcopy() */
|
int lv_copyID; ///< ID used by deepcopy().
|
||||||
list_T *lv_copylist; /* copied list used by deepcopy() */
|
list_T *lv_copylist; ///< Copied list used by deepcopy().
|
||||||
char lv_lock; /* zero, VAR_LOCKED, VAR_FIXED */
|
VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
|
||||||
list_T *lv_used_next; /* next list in used lists list */
|
list_T *lv_used_next; ///< next list in used lists list.
|
||||||
list_T *lv_used_prev; /* previous list in used lists list */
|
list_T *lv_used_prev; ///< Previous list in used lists list.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static list with 10 items. Use init_static_list() to initialize.
|
// Static list with 10 items. Use init_static_list() to initialize.
|
||||||
|
@@ -95,17 +95,19 @@ describe('b:changedtick', function()
|
|||||||
redir_exec(':let b:'))
|
redir_exec(':let b:'))
|
||||||
end)
|
end)
|
||||||
it('fails to unlock b:changedtick', function()
|
it('fails to unlock b:changedtick', function()
|
||||||
|
-- Note:
|
||||||
|
-- - unlocking VAR_FIXED variables is not an error.
|
||||||
|
-- - neither VAR_FIXED variables are reported as locked by islocked().
|
||||||
|
-- So test mostly checks that b:changedtick status does not change.
|
||||||
eq(0, exc_exec('let d = b:'))
|
eq(0, exc_exec('let d = b:'))
|
||||||
eq(1, funcs.islocked('b:changedtick'))
|
eq(1, funcs.islocked('b:changedtick'))
|
||||||
-- FIXME
|
eq(0, funcs.islocked('d.changedtick'))
|
||||||
-- eq(1, funcs.islocked('d.changedtick'))
|
|
||||||
eq('\nE46: Cannot change read-only variable "b:changedtick"',
|
eq('\nE46: Cannot change read-only variable "b:changedtick"',
|
||||||
redir_exec('unlockvar b:changedtick'))
|
redir_exec('unlockvar b:changedtick'))
|
||||||
-- FIXME
|
eq('',
|
||||||
-- eq('\nE46: Cannot change read-only variable "b:changedtick"',
|
redir_exec('unlockvar d.changedtick'))
|
||||||
-- redir_exec('unlockvar d.changedtick'))
|
|
||||||
eq(1, funcs.islocked('b:changedtick'))
|
eq(1, funcs.islocked('b:changedtick'))
|
||||||
-- eq(1, funcs.islocked('d.changedtick'))
|
eq(0, funcs.islocked('d.changedtick'))
|
||||||
end)
|
end)
|
||||||
it('is being completed', function()
|
it('is being completed', function()
|
||||||
feed(':echo b:<Tab><Home>let cmdline="<End>"<CR>')
|
feed(':echo b:<Tab><Home>let cmdline="<End>"<CR>')
|
||||||
|
Reference in New Issue
Block a user