api: allow nvim_buf_attach from lua using callbacks

This commit is contained in:
Björn Linse
2019-05-29 10:05:00 +02:00
parent 4841c46e33
commit f5c56f03bb
20 changed files with 301 additions and 59 deletions

View File

@@ -7,6 +7,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <lauxlib.h>
#include "nvim/api/buffer.h"
#include "nvim/api/private/helpers.h"
@@ -98,37 +99,62 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
return rv;
}
/// Activates buffer-update events on the channel.
/// Activates buffer-update events on a channel, or as lua callbacks.
///
/// @param channel_id
/// @param buffer Buffer handle, or 0 for current buffer
/// @param send_buffer Set to true if the initial notification should contain
/// the whole buffer. If so, the first notification will be a
/// `nvim_buf_lines_event`. Otherwise, the first notification will be
/// a `nvim_buf_changedtick_event`
/// @param opts Optional parameters. Reserved for future use.
/// a `nvim_buf_changedtick_event`. Not used for lua callbacks.
/// @param opts Optional parameters.
/// `on_lines`: lua callback received on change.
/// `on_changedtick`: lua callback received on changedtick
/// increment without text change.
/// See |api-buffer-updates-lua| for more information
/// @param[out] err Error details, if any
/// @return False when updates couldn't be enabled because the buffer isn't
/// loaded or `opts` contained an invalid key; otherwise True.
/// TODO: LUA_API_NO_EVAL
Boolean nvim_buf_attach(uint64_t channel_id,
Buffer buffer,
Boolean send_buffer,
Dictionary opts,
DictionaryOf(LuaRef) opts,
Error *err)
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
FUNC_API_SINCE(4)
{
if (opts.size > 0) {
api_set_error(err, kErrorTypeValidation, "dict isn't empty");
return false;
}
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
return false;
}
return buf_updates_register(buf, channel_id, send_buffer);
bool is_lua = (channel_id == LUA_INTERNAL_CALL);
BufUpdateCallbacks cb = BUF_UPDATE_CALLBACKS_INIT;
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");
return false;
}
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;
}
cb.on_changedtick = v->data.luaref;
v->data.integer = LUA_NOREF;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
return false;
}
}
return buf_updates_register(buf, channel_id, cb, send_buffer);
}
/// Deactivates buffer-update events on the channel.
@@ -307,7 +333,7 @@ void buffer_set_line_slice(Buffer buffer,
Integer end,
Boolean include_start,
Boolean include_end,
ArrayOf(String) replacement, // NOLINT
ArrayOf(String) replacement,
Error *err)
{
start = convert_index(start) + !include_start;
@@ -340,7 +366,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
Integer start,
Integer end,
Boolean strict_indexing,
ArrayOf(String) replacement, // NOLINT
ArrayOf(String) replacement,
Error *err)
FUNC_API_SINCE(1)
{

View File

@@ -104,6 +104,7 @@ typedef enum {
kObjectTypeString,
kObjectTypeArray,
kObjectTypeDictionary,
kObjectTypeLuaRef,
// EXT types, cannot be split or reordered, see #EXT_OBJECT_TYPE_SHIFT
kObjectTypeBuffer,
kObjectTypeWindow,
@@ -119,6 +120,7 @@ struct object {
String string;
Array array;
Dictionary dictionary;
LuaRef luaref;
} data;
};

View File

@@ -11,6 +11,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/handle.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/lua/executor.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
#include "nvim/vim.h"
@@ -1147,6 +1148,10 @@ void api_free_object(Object value)
api_free_dictionary(value.data.dictionary);
break;
case kObjectTypeLuaRef:
executor_free_luaref(value.data.luaref);
break;
default:
abort();
}

View File

@@ -48,6 +48,10 @@
.type = kObjectTypeDictionary, \
.data.dictionary = d })
#define LUAREF_OBJ(r) ((Object) { \
.type = kObjectTypeLuaRef, \
.data.luaref = r })
#define NIL ((Object) {.type = kObjectTypeNil})
#define PUT(dict, k, v) \