diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vim.c | 43 | ||||
-rw-r--r-- | src/nvim/channel.c | 4 | ||||
-rw-r--r-- | src/nvim/channel.h | 5 |
3 files changed, 46 insertions, 6 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 233fd82d3c..b5cc02e761 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1248,10 +1248,16 @@ fail: /// in a virtual terminal having the intended size. /// /// @param buffer the buffer to use (expected to be empty) -/// @param opts Optional parameters. Reserved for future use. +/// @param opts Optional parameters. +/// - on_input: lua callback for input sent, i e keypresses in terminal +/// mode. Note: keypresses are sent raw as they would be to the pty +/// master end. For instance, a carriage return is sent +/// as a "\r", not as a "\n". |textlock| applies. It is possible +/// to call |nvim_chan_send| directly in the callback however. +/// ["input", term, bufnr, data] /// @param[out] err Error details, if any /// @return Channel id, or 0 on error -Integer nvim_open_term(Buffer buffer, Dictionary opts, Error *err) +Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err) FUNC_API_SINCE(7) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -1259,13 +1265,27 @@ Integer nvim_open_term(Buffer buffer, Dictionary opts, Error *err) return 0; } - if (opts.size > 0) { - api_set_error(err, kErrorTypeValidation, "opts dict isn't empty"); - return 0; + LuaRef cb = LUA_NOREF; + for (size_t i = 0; i < opts.size; i++) { + String k = opts.items[i].key; + Object *v = &opts.items[i].value; + if (strequal("on_input", k.data)) { + if (v->type != kObjectTypeLuaRef) { + api_set_error(err, kErrorTypeValidation, + "%s is not a function", "on_input"); + return 0; + } + cb = v->data.luaref; + v->data.luaref = LUA_NOREF; + break; + } else { + api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + } } TerminalOptions topts; Channel *chan = channel_alloc(kChannelStreamInternal); + chan->stream.internal.cb = cb; topts.data = chan; // NB: overridden in terminal_check_size if a window is already // displaying the buffer @@ -1283,7 +1303,18 @@ Integer nvim_open_term(Buffer buffer, Dictionary opts, Error *err) static void term_write(char *buf, size_t size, void *data) { - // TODO(bfredl): lua callback + Channel *chan = data; + LuaRef cb = chan->stream.internal.cb; + if (cb == LUA_NOREF) { + return; + } + FIXED_TEMP_ARRAY(args, 3); + args.items[0] = INTEGER_OBJ((Integer)chan->id); + args.items[1] = BUFFER_OBJ(terminal_buf(chan->term)); + args.items[2] = STRING_OBJ(((String){ .data = buf, .size = size })); + textlock++; + nlua_call_ref(cb, "input", args, false, NULL); + textlock--; } static void term_resize(uint16_t width, uint16_t height, void *data) diff --git a/src/nvim/channel.c b/src/nvim/channel.c index db0a2ff64c..313eefd562 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -8,6 +8,7 @@ #include "nvim/eval/encode.h" #include "nvim/event/socket.h" #include "nvim/fileio.h" +#include "nvim/lua/executor.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/server.h" #include "nvim/os/shell.h" @@ -136,6 +137,8 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) *error = (const char *)e_invstream; return false; } + api_free_luaref(chan->stream.internal.cb); + chan->stream.internal.cb = LUA_NOREF; break; default: @@ -420,6 +423,7 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader // Create a loopback channel. This avoids deadlock if nvim connects to // its own named pipe. channel = channel_alloc(kChannelStreamInternal); + channel->stream.internal.cb = LUA_NOREF; rpc_start(channel); goto end; } diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 4f51a7fc78..8d14f465c1 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -43,6 +43,10 @@ typedef struct { } StderrState; typedef struct { + LuaRef cb; +} InternalState; + +typedef struct { Callback cb; dict_T *self; garray_T buffer; @@ -74,6 +78,7 @@ struct Channel { Stream socket; StdioPair stdio; StderrState err; + InternalState internal; } stream; bool is_rpc; |