mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(api): notify dict watchers on nvim_set_var and vim.g setter
Co-authored-by: bfredl <bjorn.linse@gmail.com> Co-authored-by: Christian Clason <c.clason@uni-graz.at>
This commit is contained in:
parent
1d337d4e2f
commit
c7d30c152d
@ -218,6 +218,8 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool watched = tv_dict_is_watched(dict);
|
||||
|
||||
if (del) {
|
||||
// Delete the key
|
||||
if (di == NULL) {
|
||||
@ -225,6 +227,10 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
|
||||
api_set_error(err, kErrorTypeValidation, "Key not found: %s",
|
||||
key.data);
|
||||
} else {
|
||||
// Notify watchers
|
||||
if (watched) {
|
||||
tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv);
|
||||
}
|
||||
// Return the old value
|
||||
if (retval) {
|
||||
rv = vim_to_object(&di->di_tv);
|
||||
@ -241,11 +247,16 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
|
||||
return rv;
|
||||
}
|
||||
|
||||
typval_T oldtv = TV_INITIAL_VALUE;
|
||||
|
||||
if (di == NULL) {
|
||||
// Need to create an entry
|
||||
di = tv_dict_item_alloc_len(key.data, key.size);
|
||||
tv_dict_add(dict, di);
|
||||
} else {
|
||||
if (watched) {
|
||||
tv_copy(&di->di_tv, &oldtv);
|
||||
}
|
||||
// Return the old value
|
||||
if (retval) {
|
||||
rv = vim_to_object(&di->di_tv);
|
||||
@ -255,6 +266,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva
|
||||
|
||||
// Update the value
|
||||
tv_copy(&tv, &di->di_tv);
|
||||
|
||||
// Notify watchers
|
||||
if (watched) {
|
||||
tv_dict_watcher_notify(dict, key.data, &tv, &oldtv);
|
||||
tv_clear(&oldtv);
|
||||
}
|
||||
|
||||
// Clear the temporary variable
|
||||
tv_clear(&tv);
|
||||
}
|
||||
|
@ -1781,7 +1781,7 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T
|
||||
tv_dict_add(argv[2].vval.v_dict, v);
|
||||
}
|
||||
|
||||
if (oldtv) {
|
||||
if (oldtv && oldtv->v_type != VAR_UNKNOWN) {
|
||||
dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old"));
|
||||
tv_copy(oldtv, &v->di_tv);
|
||||
tv_dict_add(argv[2].vval.v_dict, v);
|
||||
|
@ -1348,12 +1348,8 @@ void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
|
||||
}
|
||||
|
||||
if (watched) {
|
||||
if (oldtv.v_type == VAR_UNKNOWN) {
|
||||
tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, NULL);
|
||||
} else {
|
||||
tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
|
||||
tv_clear(&oldtv);
|
||||
}
|
||||
tv_dict_watcher_notify(dict, (char *)v->di_key, &v->di_tv, &oldtv);
|
||||
tv_clear(&oldtv);
|
||||
}
|
||||
|
||||
if (is_const) {
|
||||
|
@ -369,12 +369,19 @@ int nlua_setvar(lua_State *lstate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool watched = tv_dict_is_watched(dict);
|
||||
|
||||
if (del) {
|
||||
// Delete the key
|
||||
if (di == NULL) {
|
||||
// Doesn't exist, nothing to do
|
||||
return 0;
|
||||
} else {
|
||||
// Notify watchers
|
||||
if (watched) {
|
||||
tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv);
|
||||
}
|
||||
|
||||
// Delete the entry
|
||||
tv_dict_item_remove(dict, di);
|
||||
}
|
||||
@ -388,17 +395,29 @@ int nlua_setvar(lua_State *lstate)
|
||||
return luaL_error(lstate, "Couldn't convert lua value");
|
||||
}
|
||||
|
||||
typval_T oldtv = TV_INITIAL_VALUE;
|
||||
|
||||
if (di == NULL) {
|
||||
// Need to create an entry
|
||||
di = tv_dict_item_alloc_len(key.data, key.size);
|
||||
tv_dict_add(dict, di);
|
||||
} else {
|
||||
if (watched) {
|
||||
tv_copy(&di->di_tv, &oldtv);
|
||||
}
|
||||
// Clear the old value
|
||||
tv_clear(&di->di_tv);
|
||||
}
|
||||
|
||||
// Update the value
|
||||
tv_copy(&tv, &di->di_tv);
|
||||
|
||||
// Notify watchers
|
||||
if (watched) {
|
||||
tv_dict_watcher_notify(dict, key.data, &tv, &oldtv);
|
||||
tv_clear(&oldtv);
|
||||
}
|
||||
|
||||
// Clear the temporary variable
|
||||
tv_clear(&tv);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ local clear, nvim, source = helpers.clear, helpers.nvim, helpers.source
|
||||
local insert = helpers.insert
|
||||
local eq, next_msg = helpers.eq, helpers.next_msg
|
||||
local exc_exec = helpers.exc_exec
|
||||
local exec_lua = helpers.exec_lua
|
||||
local command = helpers.command
|
||||
local eval = helpers.eval
|
||||
|
||||
@ -21,6 +22,8 @@ describe('VimL dictionary notifications', function()
|
||||
-- t:) and a dictionary variable, so we generate them in the following
|
||||
-- function.
|
||||
local function gentests(dict_expr, dict_init)
|
||||
local is_g = dict_expr == 'g:'
|
||||
|
||||
local function update(opval, key)
|
||||
if not key then
|
||||
key = 'watched'
|
||||
@ -32,6 +35,28 @@ describe('VimL dictionary notifications', function()
|
||||
end
|
||||
end
|
||||
|
||||
local function update_with_api(opval, key)
|
||||
if not key then
|
||||
key = 'watched'
|
||||
end
|
||||
if opval == '' then
|
||||
exec_lua(('vim.api.nvim_del_var(\'%s\')'):format(key))
|
||||
else
|
||||
exec_lua(('vim.api.nvim_set_var(\'%s\', %s)'):format(key, opval))
|
||||
end
|
||||
end
|
||||
|
||||
local function update_with_vim_g(opval, key)
|
||||
if not key then
|
||||
key = 'watched'
|
||||
end
|
||||
if opval == '' then
|
||||
exec_lua(('vim.g.%s = nil'):format(key))
|
||||
else
|
||||
exec_lua(('vim.g.%s %s'):format(key, opval))
|
||||
end
|
||||
end
|
||||
|
||||
local function verify_echo()
|
||||
-- helper to verify that no notifications are sent after certain change
|
||||
-- to a dict
|
||||
@ -76,6 +101,18 @@ describe('VimL dictionary notifications', function()
|
||||
update('', 'watched2')
|
||||
update('')
|
||||
verify_echo()
|
||||
if is_g then
|
||||
update_with_api('"test"')
|
||||
update_with_api('"test2"', 'watched2')
|
||||
update_with_api('', 'watched2')
|
||||
update_with_api('')
|
||||
verify_echo()
|
||||
update_with_vim_g('= "test"')
|
||||
update_with_vim_g('= "test2"', 'watched2')
|
||||
update_with_vim_g('', 'watched2')
|
||||
update_with_vim_g('')
|
||||
verify_echo()
|
||||
end
|
||||
end)
|
||||
|
||||
it('is not triggered when unwatched keys are updated', function()
|
||||
@ -83,6 +120,16 @@ describe('VimL dictionary notifications', function()
|
||||
update('.= "noop2"', 'unwatched')
|
||||
update('', 'unwatched')
|
||||
verify_echo()
|
||||
if is_g then
|
||||
update_with_api('"noop"', 'unwatched')
|
||||
update_with_api('vim.g.unwatched .. "noop2"', 'unwatched')
|
||||
update_with_api('', 'unwatched')
|
||||
verify_echo()
|
||||
update_with_vim_g('= "noop"', 'unwatched')
|
||||
update_with_vim_g('= vim.g.unwatched .. "noop2"', 'unwatched')
|
||||
update_with_vim_g('', 'unwatched')
|
||||
verify_echo()
|
||||
end
|
||||
end)
|
||||
|
||||
it('is triggered by remove()', function()
|
||||
@ -92,6 +139,22 @@ describe('VimL dictionary notifications', function()
|
||||
verify_value({old = 'test'})
|
||||
end)
|
||||
|
||||
if is_g then
|
||||
it('is triggered by remove() when updated with nvim_*_var', function()
|
||||
update_with_api('"test"')
|
||||
verify_value({new = 'test'})
|
||||
nvim('command', 'call remove('..dict_expr..', "watched")')
|
||||
verify_value({old = 'test'})
|
||||
end)
|
||||
|
||||
it('is triggered by remove() when updated with vim.g', function()
|
||||
update_with_vim_g('= "test"')
|
||||
verify_value({new = 'test'})
|
||||
nvim('command', 'call remove('..dict_expr..', "watched")')
|
||||
verify_value({old = 'test'})
|
||||
end)
|
||||
end
|
||||
|
||||
it('is triggered by extend()', function()
|
||||
update('= "xtend"')
|
||||
verify_value({new = 'xtend'})
|
||||
|
Loading…
Reference in New Issue
Block a user