aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/api/vim.c43
-rw-r--r--src/nvim/channel.c4
-rw-r--r--src/nvim/channel.h5
-rw-r--r--test/functional/api/vim_spec.lua72
4 files changed, 118 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;
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index f030cfe00e..c95c24fabe 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -22,6 +22,7 @@ local source = helpers.source
local next_msg = helpers.next_msg
local tmpname = helpers.tmpname
local write_file = helpers.write_file
+local exec_lua = helpers.exec_lua
local pcall_err = helpers.pcall_err
local format_string = helpers.format_string
@@ -2264,6 +2265,9 @@ describe('API', function()
[2] = {background = tonumber('0xffff40'), bg_indexed = true};
[3] = {background = Screen.colors.Plum1, fg_indexed = true, foreground = tonumber('0x00e000')};
[4] = {bold = true, reverse = true, background = Screen.colors.Plum1};
+ [5] = {foreground = Screen.colors.Blue, background = Screen.colors.LightMagenta, bold = true};
+ [6] = {bold = true};
+ [7] = {reverse = true, background = Screen.colors.LightMagenta};
})
end)
@@ -2311,6 +2315,74 @@ describe('API', function()
|
]]}
end)
+
+ it('can handle input', function()
+ screen:try_resize(50, 10)
+ eq({3, 2}, exec_lua [[
+ buf = vim.api.nvim_create_buf(1,1)
+
+ stream = ''
+ do_the_echo = false
+ function input(_,t1,b1,data)
+ stream = stream .. data
+ _G.vals = {t1, b1}
+ if do_the_echo then
+ vim.api.nvim_chan_send(t1, data)
+ end
+ end
+
+ term = vim.api.nvim_open_term(buf, {on_input=input})
+ vim.api.nvim_open_win(buf, true, {width=40, height=5, row=1, col=1, relative='editor'})
+ return {term, buf}
+ ]])
+
+ screen:expect{grid=[[
+ |
+ {0:~}{1:^ }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+
+ feed 'iba<c-x>bla'
+ screen:expect{grid=[[
+ |
+ {0:~}{7: }{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:-- TERMINAL --} |
+ ]]}
+
+ eq('ba\024bla', exec_lua [[ return stream ]])
+ eq({3,2}, exec_lua [[ return vals ]])
+
+ exec_lua [[ do_the_echo = true ]]
+ feed 'herrejösses!'
+
+ screen:expect{grid=[[
+ |
+ {0:~}{1:herrejösses!}{7: }{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~}{1: }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {6:-- TERMINAL --} |
+ ]]}
+ eq('ba\024blaherrejösses!', exec_lua [[ return stream ]])
+ end)
end)
describe('nvim_del_mark', function()