api/lua: add on_detach to nvim_buf_attach

This commit is contained in:
Björn Linse
2019-06-15 11:07:00 +02:00
parent 93f8c2793c
commit 64cdf9f78a
5 changed files with 140 additions and 10 deletions

View File

@@ -12,6 +12,7 @@
#include "nvim/api/buffer.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
#include "nvim/lua/executor.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
@@ -137,24 +138,38 @@ Boolean nvim_buf_attach(uint64_t channel_id,
if (is_lua && strequal("on_lines", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
return false;
goto error;
}
cb.on_lines = v->data.luaref;
v->data.integer = 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");
return false;
goto error;
}
cb.on_changedtick = v->data.luaref;
v->data.integer = 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.integer = LUA_NOREF;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
return false;
goto error;
}
}
return buf_updates_register(buf, channel_id, cb, send_buffer);
error:
// TODO(bfredl): ASAN build should check that the ref table is empty?
executor_free_luaref(cb.on_lines);
executor_free_luaref(cb.on_changedtick);
executor_free_luaref(cb.on_detach);
return false;
}
/// Deactivates buffer-update events on the channel.

View File

@@ -456,8 +456,9 @@ typedef TV_DICTITEM_STRUCT(sizeof("changedtick")) ChangedtickDictItem;
typedef struct {
LuaRef on_lines;
LuaRef on_changedtick;
LuaRef on_detach;
} BufUpdateCallbacks;
#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF }
#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF }
#define BUF_HAS_QF_ENTRY 1
#define BUF_HAS_LL_ENTRY 2

View File

@@ -143,7 +143,21 @@ void buf_updates_unregister_all(buf_T *buf)
}
for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) {
free_update_callbacks(kv_A(buf->update_callbacks, i));
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
if (cb.on_detach != LUA_NOREF) {
Array args = ARRAY_DICT_INIT;
Object items[1];
args.size = 1;
args.items = items;
// the first argument is always the buffer handle
args.items[0] = BUFFER_OBJ(buf->handle);
textlock++;
executor_exec_lua_cb(cb.on_detach, "detach", args, false);
textlock--;
}
free_update_callbacks(cb);
}
kv_destroy(buf->update_callbacks);
kv_init(buf->update_callbacks);
@@ -237,13 +251,14 @@ void buf_updates_send_changes(buf_T *buf,
args.items[4] = INTEGER_OBJ(firstline - 1 + num_added);
textlock++;
Object res = executor_exec_lua_cb(cb.on_lines, "lines", args);
Object res = executor_exec_lua_cb(cb.on_lines, "lines", args, true);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
free_update_callbacks(cb);
keep = false;
}
api_free_object(res);
}
if (keep) {
kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i);
@@ -276,13 +291,15 @@ void buf_updates_changedtick(buf_T *buf)
args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
textlock++;
Object res = executor_exec_lua_cb(cb.on_changedtick, "changedtick", args);
Object res = executor_exec_lua_cb(cb.on_changedtick, "changedtick",
args, true);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
free_update_callbacks(cb);
keep = false;
}
api_free_object(res);
}
if (keep) {
kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i);

View File

@@ -520,7 +520,8 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err)
return nlua_pop_Object(lstate, false, err);
}
Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args)
Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args,
bool retval)
{
lua_State *const lstate = nlua_enter();
nlua_pushref(lstate, ref);
@@ -529,7 +530,7 @@ Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args)
nlua_push_Object(lstate, args.items[i]);
}
if (lua_pcall(lstate, (int)args.size+1, 1, 0)) {
if (lua_pcall(lstate, (int)args.size+1, retval ? 1 : 0, 0)) {
// TODO(bfredl): callbacks:s might not always be msg-safe, for instance
// lua callbacks for redraw events. Later on let the caller deal with the
// error instead.
@@ -538,7 +539,11 @@ Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args)
}
Error err = ERROR_INIT;
return nlua_pop_Object(lstate, false, &err);
if (retval) {
return nlua_pop_Object(lstate, false, &err);
} else {
return NIL;
}
}
/// Run lua string