diff options
author | Björn Linse <bjorn.linse@gmail.com> | 2019-05-29 10:05:00 +0200 |
---|---|---|
committer | Björn Linse <bjorn.linse@gmail.com> | 2019-06-04 13:45:20 +0200 |
commit | f5c56f03bb9ee25c3d931034497dc76a5591b770 (patch) | |
tree | 1d6f3a67cef29ed775d51ae6c65e48c3ce8155c4 /src/nvim/buffer_updates.c | |
parent | 4841c46e3384b09caaaded4936cde7be461d1b3c (diff) | |
download | rneovim-f5c56f03bb9ee25c3d931034497dc76a5591b770.tar.gz rneovim-f5c56f03bb9ee25c3d931034497dc76a5591b770.tar.bz2 rneovim-f5c56f03bb9ee25c3d931034497dc76a5591b770.zip |
api: allow nvim_buf_attach from lua using callbacks
Diffstat (limited to 'src/nvim/buffer_updates.c')
-rw-r--r-- | src/nvim/buffer_updates.c | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index 9d9c998a68..2515e3f8aa 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -5,19 +5,30 @@ #include "nvim/memline.h" #include "nvim/api/private/helpers.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/lua/executor.h" #include "nvim/assert.h" #include "nvim/buffer.h" +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "buffer_updates.c.generated.h" +#endif + // Register a channel. Return True if the channel was added, or already added. // Return False if the channel couldn't be added because the buffer is // unloaded. -bool buf_updates_register(buf_T *buf, uint64_t channel_id, bool send_buffer) +bool buf_updates_register(buf_T *buf, uint64_t channel_id, + BufUpdateCallbacks cb, bool send_buffer) { // must fail if the buffer isn't loaded if (buf->b_ml.ml_mfp == NULL) { return false; } + if (channel_id == LUA_INTERNAL_CALL) { + kv_push(buf->update_callbacks, cb); + return true; + } + // count how many channels are currently watching the buffer size_t size = kv_size(buf->update_channels); if (size) { @@ -69,6 +80,11 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id, bool send_buffer) return true; } +bool buf_updates_active(buf_T *buf) +{ + return kv_size(buf->update_channels) || kv_size(buf->update_callbacks); +} + void buf_updates_send_end(buf_T *buf, uint64_t channelid) { Array args = ARRAY_DICT_INIT; @@ -125,6 +141,12 @@ void buf_updates_unregister_all(buf_T *buf) kv_destroy(buf->update_channels); kv_init(buf->update_channels); } + + for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) { + free_update_callbacks(kv_A(buf->update_callbacks, i)); + } + kv_destroy(buf->update_callbacks); + kv_init(buf->update_callbacks); } void buf_updates_send_changes(buf_T *buf, @@ -133,6 +155,10 @@ void buf_updates_send_changes(buf_T *buf, int64_t num_removed, bool send_tick) { + if (!buf_updates_active(buf)) { + return; + } + // if one the channels doesn't work, put its ID here so we can remove it later uint64_t badchannelid = 0; @@ -183,6 +209,47 @@ void buf_updates_send_changes(buf_T *buf, ELOG("Disabling buffer updates for dead channel %"PRIu64, badchannelid); buf_updates_unregister(buf, badchannelid); } + + // notify each of the active 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); + bool keep = true; + if (cb.on_lines != LUA_NOREF) { + Array args = ARRAY_DICT_INIT; + Object items[5]; + args.size = 5; + args.items = items; + + // the first argument is always the buffer handle + args.items[0] = BUFFER_OBJ(buf->handle); + + // next argument is b:changedtick + args.items[1] = send_tick ? INTEGER_OBJ(buf_get_changedtick(buf)) : NIL; + + // the first line that changed (zero-indexed) + args.items[2] = INTEGER_OBJ(firstline - 1); + + // the last line that was changed + args.items[3] = INTEGER_OBJ(firstline - 1 + num_removed); + + // the last line in the updated range + args.items[4] = INTEGER_OBJ(firstline - 1 + num_added); + + textlock++; + Object res = executor_exec_lua_cb(cb.on_lines, "lines", args); + textlock--; + + if (res.type == kObjectTypeBoolean && res.data.boolean == true) { + free_update_callbacks(cb); + keep = false; + } + } + if (keep) { + kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i); + } + } + kv_size(buf->update_callbacks) = j; } void buf_updates_changedtick(buf_T *buf) @@ -192,6 +259,36 @@ void buf_updates_changedtick(buf_T *buf) uint64_t channel_id = kv_A(buf->update_channels, i); buf_updates_changedtick_single(buf, channel_id); } + size_t j = 0; + for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) { + BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i); + bool keep = true; + if (cb.on_changedtick != LUA_NOREF) { + Array args = ARRAY_DICT_INIT; + Object items[2]; + args.size = 2; + args.items = items; + + // the first argument is always the buffer handle + args.items[0] = BUFFER_OBJ(buf->handle); + + // next argument is b:changedtick + args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf)); + + textlock++; + Object res = executor_exec_lua_cb(cb.on_changedtick, "changedtick", args); + textlock--; + + if (res.type == kObjectTypeBoolean && res.data.boolean == true) { + free_update_callbacks(cb); + keep = false; + } + } + if (keep) { + kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i); + } + } + kv_size(buf->update_callbacks) = j; } void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id) @@ -209,3 +306,9 @@ void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id) // don't try and clean up dead channels here rpc_send_event(channel_id, "nvim_buf_changedtick_event", args); } + +static void free_update_callbacks(BufUpdateCallbacks cb) +{ + executor_free_luaref(cb.on_lines); + executor_free_luaref(cb.on_changedtick); +} |