aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerw7 <erw7.github@gmail.com>2021-11-12 00:07:03 +0900
committerzeertzjq <zeertzjq@outlook.com>2022-03-12 19:23:45 +0800
commit5051510ade5f171c1239906c8638e804356186fe (patch)
tree43ce21d99a58a7c77baf6f98d0c5234070db93e4
parentab456bc304965d83585cd248284cb36c96927457 (diff)
downloadrneovim-5051510ade5f171c1239906c8638e804356186fe.tar.gz
rneovim-5051510ade5f171c1239906c8638e804356186fe.tar.bz2
rneovim-5051510ade5f171c1239906c8638e804356186fe.zip
fix(channel): fix channel consistency
- Fix the problem that chanclose() does not work for channel created by nvim_open_term(). - Fix the problem that the loopback channel is not released. - Fix the error message when sending raw data to the loopback channel.
-rw-r--r--src/nvim/api/vim.c1
-rw-r--r--src/nvim/channel.c16
-rw-r--r--src/nvim/channel.h1
-rw-r--r--src/nvim/terminal.c8
-rw-r--r--test/functional/core/channels_spec.lua21
-rw-r--r--test/functional/terminal/channel_spec.lua10
6 files changed, 52 insertions, 5 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index b691dee2ef..c7ccc6bfeb 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1140,6 +1140,7 @@ Integer nvim_open_term(Buffer buffer, DictionaryOf(LuaRef) opts, Error *err)
TerminalOptions topts;
Channel *chan = channel_alloc(kChannelStreamInternal);
chan->stream.internal.cb = cb;
+ chan->stream.internal.closed = false;
topts.data = chan;
// NB: overridden in terminal_check_size if a window is already
// displaying the buffer
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index d79c0acc4a..f87b3a2f8f 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -138,8 +138,14 @@ 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;
+ if (chan->term) {
+ api_free_luaref(chan->stream.internal.cb);
+ chan->stream.internal.cb = LUA_NOREF;
+ chan->stream.internal.closed = true;
+ terminal_close(chan->term, 0);
+ } else {
+ channel_decref(chan);
+ }
break;
default:
@@ -536,7 +542,11 @@ size_t channel_send(uint64_t id, char *data, size_t len, bool data_owned, const
}
if (chan->streamtype == kChannelStreamInternal) {
- if (!chan->term) {
+ if (chan->is_rpc) {
+ *error = _("Can't send raw data to rpc channel");
+ goto retfree;
+ }
+ if (!chan->term || chan->stream.internal.closed) {
*error = _("Can't send data to closed stream");
goto retfree;
}
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index 50d6b3600a..5cec5731eb 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -44,6 +44,7 @@ typedef struct {
typedef struct {
LuaRef cb;
+ bool closed;
} InternalState;
typedef struct {
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 1c26e46a21..a76a806b80 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -317,10 +317,14 @@ void terminal_close(Terminal *term, int status)
term->opts.close_cb(term->opts.data);
}
} else if (!only_destroy) {
- // This was called by channel_process_exit_cb() not in process_teardown().
+ // Associated channel has been closed and the editor is not exiting.
// Do not call the close callback now. Wait for the user to press a key.
char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
- snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status);
+ if (((Channel *)term->opts.data)->streamtype == kChannelStreamInternal) {
+ snprintf(msg, sizeof msg, "\r\n[Terminal closed]");
+ } else {
+ snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status);
+ }
terminal_receive(term, msg, strlen(msg));
}
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index c28300f0f4..ca52404d3b 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -10,6 +10,8 @@ local nvim_prog = helpers.nvim_prog
local is_os = helpers.is_os
local retry = helpers.retry
local expect_twostreams = helpers.expect_twostreams
+local assert_alive = helpers.assert_alive
+local pcall_err = helpers.pcall_err
describe('channels', function()
local init = [[
@@ -314,3 +316,22 @@ describe('channels', function()
eq({"notification", "exit", {id, 1, {''}}}, next_msg())
end)
end)
+
+describe('loopback', function()
+ before_each(function()
+ clear()
+ command("let chan = sockconnect('pipe', v:servername, {'rpc': v:true})")
+ end)
+
+ it('does not crash when sending raw data', function()
+ eq("Vim(call):Can't send raw data to rpc channel",
+ pcall_err(command, "call chansend(chan, 'test')"))
+ assert_alive()
+ end)
+
+ it('are released when closed', function()
+ local chans = eval('len(nvim_list_chans())')
+ command('call chanclose(chan)')
+ eq(chans - 1, eval('len(nvim_list_chans())'))
+ end)
+end)
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 7223f5ba61..a0aa8c0708 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -43,3 +43,13 @@ describe('associated channel is closed and later freed for terminal', function()
eq("Vim(call):E900: Invalid channel id", pcall_err(command, [[call chansend(id, 'test')]]))
end)
end)
+
+describe('channel created by nvim_open_term', function()
+ before_each(clear)
+
+ it('can close', function()
+ command('let id = nvim_open_term(0, {})')
+ eq("Vim(call):Can't send data to closed stream",
+ pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
+ end)
+end)