New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add notifications about variable changes #2203
Comments
The second approach(using funcrefs) is clearly more flexible, and faster than using autocmds because we wont be dealing with global events(no need to match against all registered autocmd pattenrs). Instead, each dict will have a Here are some problems with using
The result is that every terminal needs to pass data to This commit fixes the problem by changing the job API to use callbacks instead, and the result is not only a cleaner API but a faster and simpler implementation for terminals that don't need to pass data to job handlers. I plan to merge it after #2076. |
I was actually expecting a single linked list:
(a pointer to such list lives in dictionary). Main question is how to watch for keys (in my opinion this is better then watching for the whole dictionary): either have a hash pointer attached to the dictionary (+1 if operation per each and every setitem/delitem operation in best case which should be negligible, +1 if, 1 hash lookup and a VimL function call in worst case). Or attach watcher to |
I think that watching the whole dictionary is better, because plugins can simply namespace their configuration options if more granularity is required. For example, say a plugin has options split into three categories(window, buffer and syntax): let s:plugin_options = {
\ 'window_options': {},
\ 'buffer_options': {},
\ 'syntax_options': {},
\ }
call watch_dict(s:plugin_options.window_options, 's:WindowOptionChanged')
call watch_dict(s:plugin_options.buffer_options, 's:BufferOptionChanged')
call watch_dict(s:plugin_options.syntax_options, 's:SyntaxOptionChanged') Note that this does not rule out the possibility of using patterns to match variable names, though namespacing is probably better |
Problem is that dictionaries can simply be removed. Or replaced:
. You can’t cope with this without either watching the WTF is s:plugin_option and how it can be used? Especially its |
Nvm that, I'm just used to script variables but for configuring a plugin its clearly not an option |
You can use script variables for configuration: if you create configuration via functions. Not sure why would variable notifications be needed then though. Currently such notifications regarding configuration are needed just not to waste time at startup on calling loads of functions and loading loads of autoload scripts. They are not needed to receive notification about variable changes: one may just require doing all configuration via autoload functions. |
A variant of your suggestion: typedef struct dict_watcher {
struct dict_watcher *next;
void (*callback)(dict_T *dict, char *key, typval_T value, void *data);
char *pattern;
} DictWatcher; If pattern == NULL the callback will simply be invoked for every key. The same function for matching autocmds can be used for matching the patterns. The advantage is that watchers can be used by C code to implement options decoupled from nvim core. |
Another possibility: typedef struct dict_watcher {
struct dict_watcher *next;
typval_T (*callback)(dict_T *dict, char *key, typval_T value, void *data);
char *pattern;
} DictWatcher; This one will use the return value of the callback as the actual option value. If the type is |
I guess this variant is missing |
And
|
Transformation of values will be rather unexpected. I would suggest
(note |
Your'e right. If transformation is required the plugin can simply set a new value in the callback(the watcher needs to be disabled when running the callback to avoid infinite recursion) |
This could very well be used to implement #1913, options could become reserved dicts prefixed with
|
How about making |
Some thoughts about what can actually be planned:
Notifications about variable changes may be done two ways:
g:
,b:
, … “public” scope dictionaries specially and run a C equivalent oflet v:…=…|doautocmd VariableChanged g:foo
on each change (==autocmd VariableChanged g:foo
to catch changes), but only to these scope dictionaries. This is more consistent with other things that are run automatically, but is rather not flexible. Also this variant is not able to notify about changes in nested structures (e.g. forlet g:foo.bar=1
) which is not very common in plugin settings, but is still present.watch_dict_key(dictionary, key, funcref)
andwatch_dict_changes(dictionary, funcref)
(alsowatch_list_changes
, but withoutwatch_list_index
). Both functions will make NeoVim runfuncref(kind_of_change, dictionary, key, old_value)
on changes, but first is limited to one dictionary key* and intended for use with global scope (watching plugin own configuration variables) and second is intended for watching nested dictionaries that may be used for complex configuration.First is more consistent, but not flexible. Second has much more use cases.
* Maybe even only to existing so that watchers can be attached directly to
dictitem_T
, but that should increase memory usage by one pointer per each dictionary item. Current usage: two bytes (v_type, v_lock), alignment, one pointer (== two pointers if you consider the alignment), one byte for flags and at least two bytes for key.The text was updated successfully, but these errors were encountered: