aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/nvim/api/ui.c3
-rw-r--r--src/nvim/api/vim.c18
-rw-r--r--src/nvim/channel.c34
-rw-r--r--src/nvim/fileio.c10
-rw-r--r--src/nvim/tui/tui.c1
-rw-r--r--test/functional/api/vim_spec.lua2
-rw-r--r--test/functional/core/job_spec.lua15
-rw-r--r--third-party/cmake/BuildLuv.cmake3
9 files changed, 62 insertions, 28 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4b021ad6e7..47e873a845 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -67,8 +67,8 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
# If not in a git repo (e.g., a tarball) these tokens define the complete
# version string, else they are combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0)
-set(NVIM_VERSION_MINOR 2)
-set(NVIM_VERSION_PATCH 3)
+set(NVIM_VERSION_MINOR 3)
+set(NVIM_VERSION_PATCH 0)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
# API level
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index c165d38394..4cd2657561 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -213,7 +213,8 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
return;
}
- api_set_error(error, kErrorTypeValidation, "No such UI option: %s", name);
+ api_set_error(error, kErrorTypeValidation, "No such UI option: %s",
+ name.data);
#undef UI_EXT_OPTION
}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 962081cc23..07ec6e8c27 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -239,15 +239,17 @@ String nvim_command_output(String command, Error *err)
}
if (capture_local.ga_len > 1) {
- // redir always(?) prepends a newline; remove it.
- char *s = capture_local.ga_data;
- assert(s[0] == '\n');
- memmove(s, s + 1, (size_t)capture_local.ga_len);
- s[capture_local.ga_len - 1] = '\0';
- return (String) { // Caller will free the memory.
- .data = s,
- .size = (size_t)(capture_local.ga_len - 1),
+ String s = (String){
+ .data = capture_local.ga_data,
+ .size = (size_t)capture_local.ga_len,
};
+ // redir usually (except :echon) prepends a newline.
+ if (s.data[0] == '\n') {
+ memmove(s.data, s.data + 1, s.size);
+ s.data[s.size - 1] = '\0';
+ s.size = s.size - 1;
+ }
+ return s; // Caller will free the memory.
}
theend:
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 2e32af2e9a..776e2bfa86 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -237,15 +237,16 @@ void channel_create_event(Channel *chan, const char *ext_source)
#endif
}
-void channel_incref(Channel *channel)
+void channel_incref(Channel *chan)
{
- channel->refcount++;
+ chan->refcount++;
}
-void channel_decref(Channel *channel)
+void channel_decref(Channel *chan)
{
- if (!(--channel->refcount)) {
- multiqueue_put(main_loop.fast_events, free_channel_event, 1, channel);
+ if (!(--chan->refcount)) {
+ // delay free, so that libuv is done with the handles
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
}
@@ -267,18 +268,18 @@ void callback_reader_start(CallbackReader *reader)
static void free_channel_event(void **argv)
{
- Channel *channel = argv[0];
- if (channel->is_rpc) {
- rpc_free(channel);
+ Channel *chan = argv[0];
+ if (chan->is_rpc) {
+ rpc_free(chan);
}
- callback_reader_free(&channel->on_stdout);
- callback_reader_free(&channel->on_stderr);
- callback_free(&channel->on_exit);
+ callback_reader_free(&chan->on_stdout);
+ callback_reader_free(&chan->on_stderr);
+ callback_free(&chan->on_exit);
- pmap_del(uint64_t)(channels, channel->id);
- multiqueue_free(channel->events);
- xfree(channel);
+ pmap_del(uint64_t)(channels, chan->id);
+ multiqueue_free(chan->events);
+ xfree(chan);
}
static void channel_destroy_early(Channel *chan)
@@ -286,12 +287,15 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
+ pmap_del(uint64_t)(channels, chan->id);
+ chan->id = 0;
if ((--chan->refcount != 0)) {
abort();
}
- free_channel_event((void **)&chan);
+ // uv will keep a reference to handles until next loop tick, so delay free
+ multiqueue_put(main_loop.events, free_channel_event, 1, chan);
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 25653deb3e..4adff63b95 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1737,9 +1737,17 @@ failed:
xfree(buffer);
if (read_stdin) {
- /* Use stderr for stdin, makes shell commands work. */
close(0);
+#ifndef WIN32
+ // On Unix, use stderr for stdin, makes shell commands work.
ignored = dup(2);
+#else
+ // On Windows, use the console input handle for stdin.
+ HANDLE conin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING, 0, (HANDLE)NULL);
+ ignored = _open_osfhandle(conin, _O_RDONLY);
+#endif
}
if (tmpname != NULL) {
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index a7d4d49e0c..72a25b0b59 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -937,6 +937,7 @@ static void tui_set_mode(UI *ui, ModeShape mode)
int shape;
switch (c.shape) {
+ default: abort(); break;
case SHAPE_BLOCK: shape = 1; break;
case SHAPE_HOR: shape = 3; break;
case SHAPE_VER: shape = 5; break;
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 7ac20a99af..718294d941 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -73,6 +73,8 @@ describe('api', function()
it('captures command output', function()
eq('this is\nspinal tap',
nvim('command_output', [[echo "this is\nspinal tap"]]))
+ eq('no line ending!',
+ nvim('command_output', [[echon "no line ending!"]]))
end)
it('captures empty command output', function()
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 6d4cadbdc8..24bff423df 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -640,6 +640,21 @@ describe('jobs', function()
ok(string.find(err, "E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set") ~= nil)
end)
+ it('does not crash when repeatedly failing to start shell', function()
+ source([[
+ set shell=nosuchshell
+ func! DoIt()
+ call jobstart('true')
+ call jobstart('true')
+ endfunc
+ ]])
+ -- The crash only triggered if both jobs are cleaned up on the same event
+ -- loop tick. This is also prevented by try-block, so feed must be used.
+ feed_command("call DoIt()")
+ feed('<cr>') -- press RETURN
+ eq(2,eval('1+1'))
+ end)
+
it('jobstop() kills entire process tree #6530', function()
command('set shell& shellcmdflag& shellquote& shellpipe& shellredir& shellxquote&')
diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake
index 7b8ae09ec4..339264746c 100644
--- a/third-party/cmake/BuildLuv.cmake
+++ b/third-party/cmake/BuildLuv.cmake
@@ -86,7 +86,8 @@ else()
"-DCMAKE_C_FLAGS:STRING=${CMAKE_C_COMPILER_ARG1} ${LUV_INCLUDE_FLAGS} -fPIC")
endif()
-if(CMAKE_SYSTEM_NAME MATCHES ".*BSD" OR CMAKE_SYSTEM_NAME MATCHES "DragonFly")
+if(CMAKE_GENERATOR MATCHES "Unix Makefiles" AND
+ (CMAKE_SYSTEM_NAME MATCHES ".*BSD" OR CMAKE_SYSTEM_NAME MATCHES "DragonFly"))
set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} "-DCMAKE_MAKE_PROGRAM=gmake" --build .)
else()
set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} --build .)