diff options
-rw-r--r-- | src/nvim/eval.c | 10 | ||||
-rw-r--r-- | src/nvim/event/process.c | 7 | ||||
-rw-r--r-- | src/nvim/globals.h | 2 | ||||
-rw-r--r-- | src/nvim/main.c | 3 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 7 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/remote_ui.c | 2 | ||||
-rw-r--r-- | src/nvim/terminal.c | 4 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 2 | ||||
-rw-r--r-- | test/functional/job/job_spec.lua | 36 |
9 files changed, 60 insertions, 13 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a5ab57785c..006601211e 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -18987,7 +18987,7 @@ void ex_function(exarg_T *eap) emsg_funcname(e_funcexts, name); goto erret; } - if (fp->uf_calls > 0) { + if (fp->uf_refcount > 1 || fp->uf_calls > 0) { emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"), name); goto erret; @@ -21136,14 +21136,18 @@ static inline bool common_job_start(TerminalJobData *data, typval_T *rettv) { data->refcount++; Process *proc = (Process *)&data->proc; + char *cmd = xstrdup(proc->argv[0]); if (!process_spawn(proc)) { - EMSG(_(e_jobexe)); + EMSG2(_(e_jobspawn), cmd); + xfree(cmd); if (proc->type == kProcessTypePty) { xfree(data->proc.pty.term_name); - free_term_job_data(data); } + rettv->vval.v_number = proc->status; + term_job_data_decref(data); return false; } + xfree(cmd); data->id = current_job_id++; wstream_init(proc->in, 0); diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 81d4e690c3..bacbf4f8c7 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -66,7 +66,12 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL if (proc->err) { uv_close((uv_handle_t *)&proc->err->uv.pipe, NULL); } - process_close(proc); + + if (proc->type == kProcessTypeUv) { + uv_close((uv_handle_t *)&(((UvProcess *)proc)->uv), NULL); + } else { + process_close(proc); + } shell_free_argv(proc->argv); proc->status = -1; return false; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 68cb923e42..5126195841 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1107,6 +1107,8 @@ EXTERN char_u e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); EXTERN char_u e_invjob[] INIT(= N_("E900: Invalid job id")); EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full")); EXTERN char_u e_jobexe[] INIT(= N_("E902: \"%s\" is not an executable")); +EXTERN char_u e_jobspawn[] INIT(= N_( + "E903: Process for command \"%s\" could not be spawned")); EXTERN char_u e_jobnotpty[] INIT(= N_("E904: Job is not connected to a pty")); EXTERN char_u e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); EXTERN char_u e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); diff --git a/src/nvim/main.c b/src/nvim/main.c index e11db16c61..9af15924bd 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -245,6 +245,7 @@ int main(int argc, char **argv) set_vim_var_string(VV_PROGPATH, (char_u *)argv[0], -1); set_vim_var_string(VV_PROGNAME, path_tail((char_u *)argv[0]), -1); + event_init(); /* * Process the command line arguments. File names are put in the global * argument list "global_alist". @@ -275,7 +276,6 @@ int main(int argc, char **argv) if (GARGCOUNT > 1 && !silent_mode) printf(_("%d files to edit\n"), GARGCOUNT); - event_init(); full_screen = true; t_colors = 256; check_tty(¶ms); @@ -963,6 +963,7 @@ static void command_line_scan(mparm_T *parmp) } else if (STRICMP(argv[0] + argv_idx, "embed") == 0) { embedded_mode = true; parmp->headless = true; + channel_from_stdio(); } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) { #if !defined(UNIX) parmp->literal = TRUE; diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 0e3b8200c9..d8f86cefab 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -93,11 +93,6 @@ void channel_init(void) channels = pmap_new(uint64_t)(); event_strings = pmap_new(cstr_t)(); msgpack_sbuffer_init(&out_buffer); - - if (embedded_mode) { - channel_from_stdio(); - } - remote_ui_init(); } @@ -316,7 +311,7 @@ bool channel_close(uint64_t id) /// Creates an API channel from stdin/stdout. This is used when embedding /// Neovim -static void channel_from_stdio(void) +void channel_from_stdio(void) { Channel *channel = register_channel(kChannelTypeStdio); incref(channel); // stdio channels are only closed on exit diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c index 403ac13f2f..f0d92b52a0 100644 --- a/src/nvim/msgpack_rpc/remote_ui.c +++ b/src/nvim/msgpack_rpc/remote_ui.c @@ -28,7 +28,7 @@ void remote_ui_init(void) connected_uis = pmap_new(uint64_t)(); // Add handler for "attach_ui" String method = cstr_as_string("ui_attach"); - MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .async = true}; + MsgpackRpcRequestHandler handler = {.fn = remote_ui_attach, .async = false}; msgpack_rpc_add_method_handler(method, handler); method = cstr_as_string("ui_detach"); handler.fn = remote_ui_detach; diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index eb010bc190..931105717b 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -423,7 +423,9 @@ end: ui_busy_stop(); if (close) { term->opts.close_cb(term->opts.data); - do_cmdline_cmd("bwipeout!"); + if (term->buf) { + do_cmdline_cmd("bwipeout!"); + } } } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 6382993d5b..acc2ccc682 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -140,6 +140,7 @@ UI *tui_start(void) // listen for SIGWINCH signal_watcher_init(&loop, &data->winch_handle, ui); + data->winch_handle.events = queue_new_child(loop.events); signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH); ui->stop = tui_stop; @@ -179,6 +180,7 @@ static void tui_stop(UI *ui) // Destroy common stuff kv_destroy(data->invalid_regions); signal_watcher_stop(&data->winch_handle); + queue_free(data->winch_handle.events); signal_watcher_close(&data->winch_handle, NULL); // Destroy input stuff term_input_destroy(data->input); diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua index 7085d61cc7..bdaf2a7ec6 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/job/job_spec.lua @@ -6,6 +6,7 @@ local clear, eq, eval, execute, expect, feed, insert, neq, next_msg, nvim, helpers.insert, helpers.neq, helpers.next_message, helpers.nvim, helpers.nvim_dir, helpers.ok, helpers.run, helpers.session, helpers.source, helpers.stop, helpers.wait, helpers.write_file +local Screen = require('test.functional.ui.screen') describe('jobs', function() @@ -188,6 +189,41 @@ describe('jobs', function() eq({'notification', 'exit', {45, 10}}, next_msg()) end) + it('cant redefine callbacks being used by a job', function() + local screen = Screen.new() + screen:attach() + local script = [[ + function! g:JobHandler(job_id, data, event) + endfunction + + let g:callbacks = { + \ 'on_stdout': function('g:JobHandler'), + \ 'on_stderr': function('g:JobHandler'), + \ 'on_exit': function('g:JobHandler') + \ } + let job = jobstart('cat -', g:callbacks) + ]] + source(script) + feed(':function! g:JobHandler(job_id, data, event)<cr>') + feed(':endfunction<cr>') + screen:expect([[ + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + ~ | + :function! g:JobHandler(job_id, data, event) | + : :endfunction | + E127: Cannot redefine function JobHandler: It is in u| + se | + Press ENTER or type command to continue^ | + ]]) + end) + describe('jobwait', function() it('returns a list of status codes', function() source([[ |