buffer updates: add on_reload callback and handle it in treesitter parser

This commit is contained in:
Björn Linse
2021-02-07 07:32:19 +01:00
parent fa5f583981
commit 94622ca66b
9 changed files with 146 additions and 62 deletions

View File

@@ -119,6 +119,10 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err)
/// - on_detach: Lua callback invoked on detach. Args:
/// - the string "detach"
/// - buffer handle
/// - on_reload: Lua callback invoked on reload. The entire buffer
/// content should be considered changed. Args:
/// - the string "detach"
/// - buffer handle
/// - utf_sizes: include UTF-32 and UTF-16 size of the replaced
/// region, as args to `on_lines`.
/// - preview: also attach to command preview (i.e. 'inccommand')
@@ -141,50 +145,57 @@ Boolean nvim_buf_attach(uint64_t channel_id,
bool is_lua = (channel_id == LUA_INTERNAL_CALL);
BufUpdateCallbacks cb = BUF_UPDATE_CALLBACKS_INIT;
struct {
const char *name;
LuaRef *dest;
} cbs[] = {
{ "on_lines", &cb.on_lines },
{ "on_bytes", &cb.on_bytes },
{ "on_changedtick", &cb.on_changedtick },
{ "on_detach", &cb.on_detach },
{ "on_reload", &cb.on_reload },
{ NULL, NULL },
};
for (size_t i = 0; i < opts.size; i++) {
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
if (is_lua && strequal("on_lines", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
goto error;
bool key_used = false;
if (is_lua) {
for (size_t j = 0; cbs[j].name; j++) {
if (strequal(cbs[j].name, k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation,
"%s is not a function", cbs[j].name);
goto error;
}
*(cbs[j].dest) = v->data.luaref;
v->data.luaref = LUA_NOREF;
key_used = true;
break;
}
}
cb.on_lines = v->data.luaref;
v->data.luaref = LUA_NOREF;
} else if (is_lua && strequal("on_bytes", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
goto error;
if (key_used) {
continue;
} else if (strequal("utf_sizes", k.data)) {
if (v->type != kObjectTypeBoolean) {
api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
goto error;
}
cb.utf_sizes = v->data.boolean;
key_used = true;
} else if (strequal("preview", k.data)) {
if (v->type != kObjectTypeBoolean) {
api_set_error(err, kErrorTypeValidation, "preview must be boolean");
goto error;
}
cb.preview = v->data.boolean;
key_used = true;
}
cb.on_bytes = v->data.luaref;
v->data.luaref = LUA_NOREF;
} else if (is_lua && strequal("on_changedtick", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
goto error;
}
cb.on_changedtick = v->data.luaref;
v->data.luaref = LUA_NOREF;
} else if (is_lua && strequal("on_detach", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
goto error;
}
cb.on_detach = v->data.luaref;
v->data.luaref = LUA_NOREF;
} else if (is_lua && strequal("utf_sizes", k.data)) {
if (v->type != kObjectTypeBoolean) {
api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
goto error;
}
cb.utf_sizes = v->data.boolean;
} else if (is_lua && strequal("preview", k.data)) {
if (v->type != kObjectTypeBoolean) {
api_set_error(err, kErrorTypeValidation, "preview must be boolean");
goto error;
}
cb.preview = v->data.boolean;
} else {
}
if (!key_used) {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
goto error;
}

View File

@@ -596,7 +596,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
// Disable buffer-updates for the current buffer.
// No need to check `unload_buf`: in that case the function returned above.
buf_updates_unregister_all(buf);
buf_updates_unload(buf, false);
/*
* Remove the buffer from the list.
@@ -821,7 +821,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
buf_updates_unregister_all(buf);
buf_updates_unload(buf, false);
}
/*

View File

@@ -488,11 +488,12 @@ typedef struct {
LuaRef on_bytes;
LuaRef on_changedtick;
LuaRef on_detach;
LuaRef on_reload;
bool utf_sizes;
bool preview;
} BufUpdateCallbacks;
#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF, \
LUA_NOREF, false, false }
LUA_NOREF, LUA_NOREF, false, false }
EXTERN int curbuf_splice_pending INIT(= 0);

View File

@@ -135,7 +135,7 @@ void buf_updates_unregister(buf_T *buf, uint64_t channelid)
}
}
void buf_updates_unregister_all(buf_T *buf)
void buf_updates_unload(buf_T *buf, bool can_reload)
{
size_t size = kv_size(buf->update_channels);
if (size) {
@@ -146,9 +146,20 @@ void buf_updates_unregister_all(buf_T *buf)
kv_init(buf->update_channels);
}
size_t j = 0;
for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) {
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
if (cb.on_detach != LUA_NOREF) {
LuaRef thecb = LUA_NOREF;
bool keep = false;
if (can_reload && cb.on_reload != LUA_NOREF) {
keep = true;
thecb = cb.on_reload;
} else if (cb.on_detach != LUA_NOREF) {
thecb = cb.on_detach;
}
if (thecb != LUA_NOREF) {
Array args = ARRAY_DICT_INIT;
Object items[1];
args.size = 1;
@@ -158,15 +169,24 @@ void buf_updates_unregister_all(buf_T *buf)
args.items[0] = BUFFER_OBJ(buf->handle);
textlock++;
nlua_call_ref(cb.on_detach, "detach", args, false, NULL);
nlua_call_ref(thecb, keep ? "reload" : "detach", args, false, NULL);
textlock--;
}
free_update_callbacks(cb);
if (keep) {
kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i);
} else {
free_update_callbacks(cb);
}
}
kv_size(buf->update_callbacks) = j;
if (kv_size(buf->update_callbacks) == 0) {
kv_destroy(buf->update_callbacks);
kv_init(buf->update_callbacks);
}
kv_destroy(buf->update_callbacks);
kv_init(buf->update_callbacks);
}
void buf_updates_send_changes(buf_T *buf,
linenr_T firstline,
int64_t num_added,

View File

@@ -2537,13 +2537,13 @@ int do_ecmd(
goto theend;
}
u_unchanged(curbuf);
buf_updates_unregister_all(curbuf);
buf_updates_unload(curbuf, false);
buf_freeall(curbuf, BFA_KEEP_UNDO);
// Tell readfile() not to clear or reload undo info.
readfile_flags = READ_KEEP_UNDO;
} else {
buf_updates_unregister_all(curbuf);
buf_updates_unload(curbuf, false);
buf_freeall(curbuf, 0); // Free all things for buffer.
}
// If autocommands deleted the buffer we were going to re-edit, give

View File

@@ -5076,7 +5076,8 @@ void buf_reload(buf_T *buf, int orig_mode)
// Mark all undo states as changed.
u_unchanged(curbuf);
}
buf_updates_unregister_all(curbuf);
buf_updates_unload(curbuf, true);
curbuf->b_mod_set = true;
}
}
xfree(ea.cmd);