diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | cmake/PreventInTreeBuilds.cmake | 23 | ||||
-rw-r--r-- | runtime/autoload/remote/host.vim | 1 | ||||
-rw-r--r-- | src/nvim/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 16 | ||||
-rw-r--r-- | src/nvim/terminal.c | 2 | ||||
-rw-r--r-- | src/nvim/window.c | 2 | ||||
-rw-r--r-- | test/functional/terminal/ex_terminal_spec.lua | 26 |
8 files changed, 63 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a6a9accea..93e153be53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,9 @@ endif() # Point CMake at any custom modules we may ship list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") +# We don't support building in-tree. +include(PreventInTreeBuilds) + # Prefer our bundled versions of dependencies. set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies") if(CMAKE_CROSSCOMPILING AND NOT UNIX) diff --git a/cmake/PreventInTreeBuilds.cmake b/cmake/PreventInTreeBuilds.cmake new file mode 100644 index 0000000000..9c0ce1c0a2 --- /dev/null +++ b/cmake/PreventInTreeBuilds.cmake @@ -0,0 +1,23 @@ +function(PreventInTreeBuilds) + get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + + if("${srcdir}" STREQUAL "${bindir}") + message("") + message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + message("Neovim doesn't support in-tree builds. It's recommended that you") + message("use a build/ subdirectory:") + message(" mkdir build") + message(" cd build") + message(" cmake <OPTIONS> ..") + message("") + message("Make sure to cleanup some CMake artifacts from this failed build") + message("with:") + message(" rm -rf CMakeFiles CMakeCache.txt") + message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + message("") + message(FATAL_ERROR "Stopping build.") + endif() +endfunction() + +PreventInTreeBuilds() diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim index d4e8e98bc0..1f30b91ab8 100644 --- a/runtime/autoload/remote/host.vim +++ b/runtime/autoload/remote/host.vim @@ -191,6 +191,7 @@ function! s:RegistrationCommands(host) abort let pattern = s:plugin_patterns[a:host] let paths = globpath(&rtp, 'rplugin/'.a:host.'/'.pattern, 0, 1) let paths = map(paths, 'tr(v:val,"\\","/")') " Normalize slashes #4795 + let paths = uniq(sort(paths)) if empty(paths) return [] endif diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 59582d0734..cbea6a05c9 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -156,7 +156,7 @@ foreach(sfile ${NEOVIM_SOURCES} ${GENERATED_API_DISPATCH}) get_filename_component(full_d ${sfile} PATH) file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}") - if(${d} MATCHES "^[.][.]") + if(${d} MATCHES "^([.][.]|auto/)") file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}") endif() get_filename_component(f ${sfile} NAME) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0b1fd6670e..ac8b675834 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -405,7 +405,7 @@ typedef struct { LibuvProcess uv; PtyProcess pty; } proc; - Stream in, out, err; + Stream in, out, err; // Initialized in common_job_start(). Terminal *term; bool stopped; bool exited; @@ -21739,7 +21739,7 @@ static inline TerminalJobData *common_job_init(char **argv, if (!pty) { proc->err = &data->err; } - proc->cb = on_process_exit; + proc->cb = eval_job_process_exit_cb; proc->events = data->events; proc->detach = detach; proc->cwd = cwd; @@ -21923,7 +21923,7 @@ static void on_job_output(Stream *stream, TerminalJobData *data, RBuffer *buf, rbuffer_consumed(buf, count); } -static void on_process_exit(Process *proc, int status, void *d) +static void eval_job_process_exit_cb(Process *proc, int status, void *d) { TerminalJobData *data = d; if (data->term && !data->exited) { @@ -21947,9 +21947,15 @@ static void on_process_exit(Process *proc, int status, void *d) static void term_write(char *buf, size_t size, void *d) { - TerminalJobData *data = d; + TerminalJobData *job = d; + if (job->in.closed) { + // If the backing stream was closed abruptly, there may be write events + // ahead of the terminal close event. Just ignore the writes. + ILOG("write failed: stream is closed"); + return; + } WBuffer *wbuf = wstream_new_buffer(xmemdup(buf, size), size, 1, xfree); - wstream_write(&data->in, wbuf); + wstream_write(&job->in, wbuf); } static void term_resize(uint16_t width, uint16_t height, void *d) diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 8401343d7a..499716a7a8 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -366,10 +366,10 @@ void terminal_resize(Terminal *term, uint16_t width, uint16_t height) void terminal_enter(void) { buf_T *buf = curbuf; + assert(buf->terminal); // Should only be called when curbuf has a terminal. TerminalState state, *s = &state; memset(s, 0, sizeof(TerminalState)); s->term = buf->terminal; - assert(s->term && "should only be called when curbuf has a terminal"); // Ensure the terminal is properly sized. terminal_resize(s->term, 0, 0); diff --git a/src/nvim/window.c b/src/nvim/window.c index e9a66ad907..0be586c606 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -482,7 +482,7 @@ wingotofile: } static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, - long Prenum) + int64_t Prenum) { size_t len = xstrlcpy((char *)bufp, cmd, bufsize); diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 6f929f17e4..09b4eaa8d5 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -13,13 +13,19 @@ describe(':terminal', function() clear() screen = Screen.new(50, 4) screen:attach({rgb=false}) + -- shell-test.c is a fake shell that prints its arguments and exits. nvim('set_option', 'shell', nvim_dir..'/shell-test') nvim('set_option', 'shellcmdflag', 'EXE') - end) + -- Invokes `:terminal {cmd}` using a fake shell (shell-test.c) which prints + -- the {cmd} and exits immediately . + local function terminal_run_fake_shell_cmd(cmd) + execute("terminal "..(cmd and cmd or "")) + end + it('with no argument, acts like termopen()', function() - execute('terminal') + terminal_run_fake_shell_cmd() wait() screen:expect([[ ready $ | @@ -30,7 +36,7 @@ describe(':terminal', function() end) it('executes a given command through the shell', function() - execute('terminal echo hi') + terminal_run_fake_shell_cmd('echo hi') wait() screen:expect([[ ready $ echo hi | @@ -41,7 +47,7 @@ describe(':terminal', function() end) it('allows quotes and slashes', function() - execute([[terminal echo 'hello' \ "world"]]) + terminal_run_fake_shell_cmd([[echo 'hello' \ "world"]]) wait() screen:expect([[ ready $ echo 'hello' \ "world" | @@ -58,4 +64,16 @@ describe(':terminal', function() -- Verify that BufNew actually fired (else the test is invalid). eq('foo', eval('&shell')) end) + + it('ignores writes if the backing stream closes', function() + terminal_run_fake_shell_cmd() + helpers.feed('iiXXXXXXX') + wait() + -- Race: Though the shell exited (and streams were closed by SIGCHLD + -- handler), :terminal cleanup is pending on the main-loop. + -- This write should be ignored (not crash, #5445). + helpers.feed('iiYYYYYYY') + wait() + end) + end) |