aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-05-02 21:10:01 +0200
committerbfredl <bjorn.linse@gmail.com>2022-12-31 13:25:26 +0100
commit43e8ec92de9e0850e7d202cb7ff9051bc408447e (patch)
treefcaef65604e05fb9cc34cf7543c7d92af9c38dcf /src
parent24488169564c39a506c235bf6a33b8e23a8cb528 (diff)
downloadrneovim-43e8ec92de9e0850e7d202cb7ff9051bc408447e.tar.gz
rneovim-43e8ec92de9e0850e7d202cb7ff9051bc408447e.tar.bz2
rneovim-43e8ec92de9e0850e7d202cb7ff9051bc408447e.zip
fix(tui): more work in the TUI
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/keysets.lua2
-rw-r--r--src/nvim/api/ui.c22
-rw-r--r--src/nvim/autocmd.c17
-rw-r--r--src/nvim/event/libuv_process.c4
-rw-r--r--src/nvim/event/process.c35
-rw-r--r--src/nvim/ex_docmd.c8
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua2
-rw-r--r--src/nvim/globals.h17
-rw-r--r--src/nvim/highlight.c26
-rw-r--r--src/nvim/main.c128
-rw-r--r--src/nvim/main.h1
-rw-r--r--src/nvim/msgpack_rpc/channel.c56
-rw-r--r--src/nvim/msgpack_rpc/unpacker.c25
-rw-r--r--src/nvim/tui/input.c66
-rw-r--r--src/nvim/tui/tui.c198
-rw-r--r--src/nvim/ui.c55
-rw-r--r--src/nvim/ui_client.c98
-rw-r--r--src/nvim/ui_client.h20
18 files changed, 354 insertions, 426 deletions
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 8ded9cfa5d..8f909e937f 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -126,6 +126,8 @@ return {
"global_link";
"fallback";
"blend";
+ "fg_indexed";
+ "bg_indexed";
};
highlight_cterm = {
"bold";
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index ef6ced1ee0..e4134133ac 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -283,9 +283,9 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height, Boolean enabl
api_free_dictionary(opts);
}
-/// Tells the nvim server if focus was gained by the GUI or not
+/// Tells the nvim server if focus was gained or lost by the GUI
void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error)
- FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(11) FUNC_API_REMOTE_ONLY
{
if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(error, kErrorTypeException,
@@ -293,7 +293,7 @@ void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error)
return;
}
- autocmd_schedule_focusgained((bool)gained);
+ do_autocmd_focusgained((bool)gained);
}
/// Deactivates UI events on the channel.
@@ -415,21 +415,21 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e
return;
}
- if (strequal(name.data, "term_ttyin")) {
- if (value.type != kObjectTypeInteger) {
- api_set_error(error, kErrorTypeValidation, "term_ttyin must be a Integer");
+ if (strequal(name.data, "stdin_tty")) {
+ if (value.type != kObjectTypeBoolean) {
+ api_set_error(error, kErrorTypeValidation, "stdin_tty must be a Boolean");
return;
}
- stdin_isatty = (int)value.data.integer;
+ stdin_isatty = value.data.boolean;
return;
}
- if (strequal(name.data, "term_ttyout")) {
- if (value.type != kObjectTypeInteger) {
- api_set_error(error, kErrorTypeValidation, "term_ttyout must be a Integer");
+ if (strequal(name.data, "stdout_tty")) {
+ if (value.type != kObjectTypeBoolean) {
+ api_set_error(error, kErrorTypeValidation, "stdout_tty must be a Boolean");
return;
}
- stdout_isatty = (int)value.data.integer;
+ stdout_isatty = value.data.boolean;
return;
}
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index ab6c22ff6c..3ed3f7edf2 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -2732,22 +2732,7 @@ void do_autocmd_uienter(uint64_t chanid, bool attached)
// FocusGained
-static void focusgained_event(void **argv)
-{
- bool *gainedp = argv[0];
- do_autocmd_focusgained(*gainedp);
- xfree(gainedp);
-}
-
-void autocmd_schedule_focusgained(bool gained)
-{
- bool *gainedp = xmalloc(sizeof(*gainedp));
- *gainedp = gained;
- loop_schedule_deferred(&main_loop,
- event_create(focusgained_event, 1, gainedp));
-}
-
-static void do_autocmd_focusgained(bool gained)
+void do_autocmd_focusgained(bool gained)
{
static bool recursive = false;
static Timestamp last_time = (time_t)0;
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index cf4ff16c4d..811d96ff93 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -47,8 +47,8 @@ int libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvstdio[1].flags = UV_IGNORE;
uvproc->uvstdio[2].flags = UV_IGNORE;
- // TODO: this should just be single flag!
- if (TUI_process && !is_remote_client && !stdin_isatty) {
+ if (ui_client_forward_stdin) {
+ assert(UI_CLIENT_STDIN_FD == 3);
uvproc->uvopts.stdio_count = 4;
uvproc->uvstdio[3].data.fd = 0;
uvproc->uvstdio[3].flags = UV_INHERIT_FD;
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 52a9394e88..2fa789ac9a 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -14,6 +14,7 @@
#include "nvim/globals.h"
#include "nvim/log.h"
#include "nvim/macros.h"
+#include "nvim/main.h"
#include "nvim/os/process.h"
#include "nvim/os/pty_process.h"
#include "nvim/os/shell.h"
@@ -35,6 +36,9 @@ void __gcov_flush(void);
static bool process_is_tearing_down = false;
+// Delay exit until handles are closed, to avoid deadlocks
+static int exit_need_delay = 0;
+
/// @returns zero on success, or negative error code
int process_spawn(Process *proc, bool in, bool out, bool err)
FUNC_ATTR_NONNULL_ALL
@@ -398,16 +402,41 @@ static void process_close_handles(void **argv)
exit_need_delay--;
}
+static void exit_delay_cb(uv_timer_t *handle)
+{
+ uv_timer_stop(&main_loop.exit_delay_timer);
+ multiqueue_put(main_loop.fast_events, exit_event, 1, main_loop.exit_delay_timer.data);
+}
+
+static void exit_event(void **argv)
+{
+ int status = (int)(intptr_t)argv[0];
+ if (exit_need_delay) {
+ main_loop.exit_delay_timer.data = argv[0];
+ uv_timer_start(&main_loop.exit_delay_timer, exit_delay_cb, 0, 0);
+ return;
+ }
+
+ if (!exiting) {
+ os_exit(status);
+ }
+}
+
+void exit_from_channel(int status)
+{
+ multiqueue_put(main_loop.fast_events, exit_event, 1, status);
+}
+
static void on_process_exit(Process *proc)
{
Loop *loop = proc->loop;
ILOG("exited: pid=%d status=%d stoptime=%" PRIu64, proc->pid, proc->status,
proc->stopped_time);
- if (TUI_process && !is_remote_client) {
- // Set only in "builtin" TUI
- server_process_exit_status = proc->status;
+ if (ui_client_channel_id) {
+ exit_from_channel(proc->status);
}
+
// Process has terminated, but there could still be data to be read from the
// OS. We are still in the libuv loop, so we cannot call code that polls for
// more data directly. Instead delay the reading after the libuv loop by
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index b99df64a3d..bb03c220b6 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1931,9 +1931,11 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
profile_cmd(&ea, cstack, fgetline, cookie);
- // May go to debug mode. If this happens and the ">quit" debug command is
- // used, throw an interrupt exception and skip the next command.
- dbg_check_breakpoint(&ea);
+ if (!exiting) {
+ // May go to debug mode. If this happens and the ">quit" debug command is
+ // used, throw an interrupt exception and skip the next command.
+ dbg_check_breakpoint(&ea);
+ }
if (!ea.skip && got_int) {
ea.skip = true;
(void)do_intthrow(cstack);
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 240b99ca29..55ab9fdf0e 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -363,7 +363,7 @@ for i = 1, #functions do
-- if the function recieves the array args, pass it the second argument
output:write('args, ')
end
- output:write(call_args)
+ output:write(call_args)
else
output:write('channel_id')
if fn.receives_array_args then
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index a88360696d..cce74df9a8 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -328,9 +328,6 @@ EXTERN sctx_T current_sctx INIT(= { 0, 0, 0 });
// ID of the current channel making a client API call
EXTERN uint64_t current_channel_id INIT(= 0);
-// ID of the client channel. Used by ui client
-EXTERN uint64_t ui_client_channel_id INIT(= 0);
-
EXTERN bool did_source_packages INIT(= false);
// Scope information for the code that indirectly triggered the current
@@ -494,9 +491,9 @@ EXTERN bool exiting INIT(= false);
// internal value of v:dying
EXTERN int v_dying INIT(= 0);
// is stdin a terminal?
-EXTERN int stdin_isatty INIT(= true);
+EXTERN bool stdin_isatty INIT(= true);
// is stdout a terminal?
-EXTERN int stdout_isatty INIT(= true);
+EXTERN bool stdout_isatty INIT(= true);
/// filedesc set by embedder for reading first buffer like `cmd | nvim -`
EXTERN int stdin_fd INIT(= -1);
@@ -850,14 +847,6 @@ EXTERN linenr_T printer_page_num;
EXTERN bool typebuf_was_filled INIT(= false); // received text from client
// or from feedkeys()
-EXTERN bool is_remote_client INIT(= false); // Initially the TUI is not
- // a remote client
-
-EXTERN bool TUI_process INIT(= false); // This is the TUI process
-
-
-EXTERN long server_process_exit_status INIT(= false); // Used by TUI process
-
#ifdef BACKSLASH_IN_FILENAME
EXTERN char psepc INIT(= '\\'); // normal path separator character
EXTERN char psepcN INIT(= '/'); // abnormal path separator character
@@ -1096,8 +1085,6 @@ typedef enum {
// Only filled for Win32.
EXTERN char windowsVersion[20] INIT(= { 0 });
-EXTERN int exit_need_delay INIT(= 0);
-
/// While executing a regexp and set to OPTION_MAGIC_ON or OPTION_MAGIC_OFF this
/// overrules p_magic. Otherwise set to OPTION_MAGIC_NOT_SET.
EXTERN optmagic_T magic_overruled INIT(= OPTION_MAGIC_NOT_SET);
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 774551242f..2c55e840f1 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -933,22 +933,26 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
CHECK_FLAG(dict, mask, italic, , HL_ITALIC);
CHECK_FLAG(dict, mask, reverse, , HL_INVERSE);
CHECK_FLAG(dict, mask, strikethrough, , HL_STRIKETHROUGH);
+ if (use_rgb) {
+ CHECK_FLAG(dict, mask, fg_indexed, , HL_FG_INDEXED);
+ CHECK_FLAG(dict, mask, bg_indexed, , HL_BG_INDEXED);
+ }
CHECK_FLAG(dict, mask, nocombine, , HL_NOCOMBINE);
CHECK_FLAG(dict, mask, default, _, HL_DEFAULT);
if (HAS_KEY(dict->fg)) {
- fg = object_to_color(dict->fg, "fg", true, err);
+ fg = object_to_color(dict->fg, "fg", use_rgb, err);
} else if (HAS_KEY(dict->foreground)) {
- fg = object_to_color(dict->foreground, "foreground", true, err);
+ fg = object_to_color(dict->foreground, "foreground", use_rgb, err);
}
if (ERROR_SET(err)) {
return hlattrs;
}
if (HAS_KEY(dict->bg)) {
- bg = object_to_color(dict->bg, "bg", true, err);
+ bg = object_to_color(dict->bg, "bg", use_rgb, err);
} else if (HAS_KEY(dict->background)) {
- bg = object_to_color(dict->background, "background", true, err);
+ bg = object_to_color(dict->background, "background", use_rgb, err);
}
if (ERROR_SET(err)) {
return hlattrs;
@@ -1035,11 +1039,11 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
}
}
- // apply gui mask as default for cterm mask
- if (!cterm_mask_provided) {
- cterm_mask = mask;
- }
if (use_rgb) {
+ // apply gui mask as default for cterm mask
+ if (!cterm_mask_provided) {
+ cterm_mask = mask;
+ }
hlattrs.rgb_ae_attr = mask;
hlattrs.rgb_bg_color = bg;
hlattrs.rgb_fg_color = fg;
@@ -1049,9 +1053,9 @@ HlAttrs dict2hlattrs(Dict(highlight) *dict, bool use_rgb, int *link_id, Error *e
hlattrs.cterm_fg_color = ctermfg == -1 ? 0 : ctermfg + 1;
hlattrs.cterm_ae_attr = cterm_mask;
} else {
- hlattrs.cterm_bg_color = ctermbg == -1 ? 0 : ctermbg + 1;
- hlattrs.cterm_fg_color = ctermfg == -1 ? 0 : ctermfg + 1;
- hlattrs.cterm_ae_attr = cterm_mask;
+ hlattrs.cterm_bg_color = bg == -1 ? 0 : bg + 1;
+ hlattrs.cterm_fg_color = fg == -1 ? 0 : fg + 1;
+ hlattrs.cterm_ae_attr = mask;
}
return hlattrs;
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 422495519a..c20be202e8 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -97,9 +97,6 @@
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/server.h"
#include "nvim/os/signal.h"
-#ifndef MSWIN
-# include "nvim/os/pty_process_unix.h"
-#endif
#include "nvim/tui/tui.h"
// values for "window_layout"
@@ -141,7 +138,6 @@ void event_init(void)
// early msgpack-rpc initialization
msgpack_rpc_helpers_init();
- // Initialize input events
input_init();
signal_init();
// finish mspgack-rpc initialization
@@ -283,8 +279,6 @@ int main(int argc, char **argv)
// argument list "global_alist".
command_line_scan(&params);
- open_script_files(&params);
-
nlua_init();
TIME_MSG("init lua interpreter");
@@ -297,14 +291,28 @@ int main(int argc, char **argv)
}
bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode);
- // bool is_remote_client = false; // TODO: rename to specifically for --remote-ui
- //
- if (!(is_remote_client || use_builtin_ui)) {
+
+ // don't bind the server yet, if we are using builtin ui.
+ // This will be done when nvim server has been forked from the ui process
+ if (!use_builtin_ui) {
server_init(params.listen_addr);
}
if (params.remote) {
- remote_request(&params, params.remote, params.server_addr, argc, argv);
+ remote_request(&params, params.remote, params.server_addr, argc, argv,
+ use_builtin_ui);
+ }
+
+ bool remote_ui = (ui_client_channel_id != 0);
+
+ if (use_builtin_ui && !remote_ui) {
+ ui_client_forward_stdin = !params.input_isatty;
+ uint64_t rv = ui_client_start_server(params.argc, params.argv);
+ if (!rv) {
+ os_errmsg("Failed to start Nvim server!\n");
+ getout(1);
+ }
+ ui_client_channel_id = rv;
}
if (GARGCOUNT > 0) {
@@ -360,17 +368,16 @@ int main(int argc, char **argv)
input_start(STDIN_FILENO);
}
+ if (ui_client_channel_id) {
+ ui_client_run(remote_ui); // NORETURN
+ }
+
// Wait for UIs to set up Nvim or show early messages
// and prompts (--cmd, swapfile dialog, …).
bool use_remote_ui = (embedded_mode && !headless_mode);
- TUI_process = is_remote_client || use_builtin_ui;
- if (use_remote_ui || use_builtin_ui) {
+ if (use_remote_ui) {
TIME_MSG("waiting for UI");
- if (use_remote_ui) {
- remote_ui_wait_for_attach();
- } else {
- ui_builtin_start();
- }
+ remote_ui_wait_for_attach();
TIME_MSG("done waiting for UI");
firstwin->w_prev_height = firstwin->w_height; // may have changed
}
@@ -381,36 +388,12 @@ int main(int argc, char **argv)
win_new_screensize();
TIME_MSG("clear screen");
- if (ui_client_channel_id) {
- ui_client_init(ui_client_channel_id);
- ui_client_execute(ui_client_channel_id);
- abort(); // unreachable
- }
-
- // Setting up the remote connection.
- // This has to be always after ui_builtin_start or
- // after the start of atleast one GUI
- // as size of "uis[]" must be greater than 1
- if (TUI_process) {
- input_stop(); // Stop reading input, let the UI take over.
- uint64_t rv = ui_client_start(params.argc, params.argv,
- (params.edit_type == EDIT_STDIN
- && !recoverymode));
- if (!rv) {
- // cannot continue without a channel
- // TODO: use ui_call_stop() ?
- tui_exit_safe(ui_get_by_index(1));
- ELOG("RPC: ", NULL, -1, true,
- "Could not establish connection with address : %s", params.server_addr);
- os_msg("Could not establish connection with remote server\n");
- getout(1);
- }
- // TODO: fuuu, deduplicate with ui_client_channel_id block above
- ui_client_channel_id = rv;
- ui_client_execute(ui_client_channel_id);
- abort(); // unreachable
+ // Handle "foo | nvim". EDIT_FILE may be overwritten now. #6299
+ if (edit_stdin(&params)) {
+ params.edit_type = EDIT_STDIN;
}
+ open_script_files(&params);
// Default mappings (incl. menus)
Error err = ERROR_INIT;
@@ -520,7 +503,7 @@ int main(int argc, char **argv)
// writing end of the pipe doesn't like, e.g., in case stdin and stderr
// are the same terminal: "cat | vim -".
// Using autocommands here may cause trouble...
- if ((params.edit_type == EDIT_STDIN || stdin_fd >= 0) && !recoverymode) {
+ if (params.edit_type == EDIT_STDIN && !recoverymode) {
read_stdin();
}
@@ -661,9 +644,6 @@ void os_exit(int r)
free_all_mem();
#endif
- if (TUI_process && !is_remote_client) {
- r = (int)server_process_exit_status;
- }
exit(r);
}
@@ -877,15 +857,24 @@ static uint64_t server_connect(char *server_addr, const char **errmsg)
/// Handle remote subcommands
static void remote_request(mparm_T *params, int remote_args, char *server_addr, int argc,
- char **argv)
+ char **argv, bool ui_only)
{
+ bool is_ui = strequal(argv[remote_args], "--remote-ui");
+ if (ui_only && !is_ui) {
+ // TODO(bfredl): this implies always starting the TUI.
+ // if we be smart we could delay this past should_exit
+ return;
+ }
+
const char *connect_error = NULL;
uint64_t chan = server_connect(server_addr, &connect_error);
Object rvobj = OBJECT_INIT;
- if (strequal(argv[remote_args], "--remote-ui-test")) {
+ if (is_ui) {
if (!chan) {
- emsg(connect_error);
+ os_errmsg("Remote ui failed to start: ");
+ os_errmsg(connect_error);
+ os_errmsg("\n");
exit(1);
}
@@ -965,14 +954,14 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr,
/// Decides whether text (as opposed to commands) will be read from stdin.
/// @see EDIT_STDIN
-static bool edit_stdin(bool explicit, mparm_T *parmp)
+static bool edit_stdin(mparm_T *parmp)
{
bool implicit = !headless_mode
- && !embedded_mode
+ && !(embedded_mode && stdin_fd <= 0)
&& (!exmode_active || parmp->input_neverscript)
&& !parmp->input_isatty
&& parmp->scriptin == NULL; // `-s -` was not given.
- return explicit || implicit;
+ return parmp->had_stdin_file || implicit;
}
/// Scan the command line arguments.
@@ -981,7 +970,6 @@ static void command_line_scan(mparm_T *parmp)
int argc = parmp->argc;
char **argv = parmp->argv;
int argv_idx; // index in argv[n][]
- bool had_stdin_file = false; // found explicit "-" argument
bool had_minmin = false; // found "--" argument
int want_argument; // option argument with argument
long n;
@@ -1018,7 +1006,7 @@ static void command_line_scan(mparm_T *parmp)
&& parmp->edit_type != EDIT_STDIN) {
mainerr(err_too_many_args, argv[0]);
}
- had_stdin_file = true;
+ parmp->had_stdin_file = true;
parmp->edit_type = EDIT_STDIN;
}
argv_idx = -1; // skip to next argument
@@ -1385,7 +1373,7 @@ scripterror:
path_fix_case(p);
#endif
- int alist_fnum_flag = edit_stdin(had_stdin_file, parmp)
+ int alist_fnum_flag = edit_stdin(parmp)
? 1 // add buffer nr after exp.
: 2; // add buffer number now and use curbuf
alist_add(&global_alist, p, alist_fnum_flag);
@@ -1413,18 +1401,6 @@ scripterror:
xfree(swcmd);
}
- // Handle "foo | nvim". EDIT_FILE may be overwritten now. #6299
- if (edit_stdin(had_stdin_file, parmp)) {
- parmp->edit_type = EDIT_STDIN;
- // TODO: copy
- bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode);
- if (use_builtin_ui && !is_remote_client) {
- // must be set only in builtin TUI
- // TODO
- //implicit_readstdin = true;
- }
- }
-
TIME_MSG("parsing arguments");
}
@@ -1574,11 +1550,16 @@ static void open_script_files(mparm_T *parmp)
if (parmp->scriptin) {
int error;
if (strequal(parmp->scriptin, "-")) {
- const int stdin_dup_fd = os_dup(STDIN_FILENO);
+ int stdin_dup_fd;
+ if (stdin_fd > 0) {
+ stdin_dup_fd = stdin_fd;
+ } else {
+ stdin_dup_fd = os_dup(STDIN_FILENO);
#ifdef MSWIN
- // Replace the original stdin with the console input handle.
- os_replace_stdin_to_conin();
+ // Replace the original stdin with the console input handle.
+ os_replace_stdin_to_conin();
#endif
+ }
FileDescriptor *const stdin_dup = file_open_fd_new(&error, stdin_dup_fd,
kFileReadOnly|kFileNonBlocking);
assert(stdin_dup != NULL);
@@ -2196,7 +2177,6 @@ static void usage(void)
os_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
os_msg(_(" --headless Don't start a user interface\n"));
os_msg(_(" --listen <address> Serve RPC API from this address\n"));
- os_msg(_(" --connect <address> Specify Nvim server to connect to\n"));
os_msg(_(" --noplugin Don't load plugins\n"));
os_msg(_(" --remote[-subcommand] Execute commands remotely on a server\n"));
os_msg(_(" --server <address> Specify RPC server to send commands to\n"));
diff --git a/src/nvim/main.h b/src/nvim/main.h
index 4cf8dfe026..c39fc1ed4a 100644
--- a/src/nvim/main.h
+++ b/src/nvim/main.h
@@ -45,6 +45,7 @@ typedef struct {
char *scriptin; // -s {filename}
char *scriptout; // -w/-W {filename}
bool scriptout_append; // append (-w) instead of overwrite (-W)
+ bool had_stdin_file; // explicit - as a file to edit
} mparm_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 516af20fe9..4d011dc079 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -250,8 +250,8 @@ static void parse_msgpack(Channel *channel)
ui_client_event_raw_line(p->grid_line_event);
} else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) {
p->ui_handler.fn(p->result.data.array);
- arena_mem_free(arena_finish(&p->arena));
}
+ arena_mem_free(arena_finish(&p->arena));
} else if (p->type == kMessageTypeResponse) {
ChannelCallFrame *frame = kv_last(channel->rpc.call_stack);
if (p->request_id != frame->request_id) {
@@ -299,7 +299,7 @@ static void handle_request(Channel *channel, Unpacker *p, Array args)
assert(p->type == kMessageTypeRequest || p->type == kMessageTypeNotification);
if (!p->handler.fn) {
- send_error(channel, p->type, p->request_id, p->unpack_error.msg);
+ send_error(channel, p->handler, p->type, p->request_id, p->unpack_error.msg);
api_clear_error(&p->unpack_error);
arena_mem_free(arena_finish(&p->arena));
return;
@@ -358,6 +358,7 @@ static void request_event(void **argv)
msgpack_packer response;
msgpack_packer_init(&response, &out_buffer, msgpack_sbuffer_write);
channel_write(channel, serialize_response(channel->id,
+ e->handler,
e->type,
e->request_id,
&error,
@@ -440,11 +441,13 @@ static void internal_read_event(void **argv)
wstream_release_wbuffer(buffer);
}
-static void send_error(Channel *chan, MessageType type, uint32_t id, char *err)
+static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageType type,
+ uint32_t id, char *err)
{
Error e = ERROR_INIT;
api_set_error(&e, kErrorTypeException, "%s", err);
channel_write(chan, serialize_response(chan->id,
+ handler,
type,
id,
&e,
@@ -543,26 +546,8 @@ void rpc_close(Channel *channel)
channel_decref(channel);
if (channel->streamtype == kChannelStreamStdio
- || channel->id == ui_client_channel_id) {
- multiqueue_put(main_loop.fast_events, exit_event, 0);
- }
-}
-
-static void exit_delay_cb(uv_timer_t *handle)
-{
- uv_timer_stop(&main_loop.exit_delay_timer);
- multiqueue_put(main_loop.fast_events, exit_event, 0);
-}
-
-static void exit_event(void **argv)
-{
- if (exit_need_delay) {
- uv_timer_start(&main_loop.exit_delay_timer, exit_delay_cb, 0, 0);
- return;
- }
-
- if (!exiting) {
- os_exit(0);
+ || (channel->id == ui_client_channel_id && channel->streamtype != kChannelStreamProc)) {
+ exit_from_channel(0);
}
}
@@ -612,18 +597,27 @@ static WBuffer *serialize_request(uint64_t channel_id, uint32_t request_id, cons
return rv;
}
-static WBuffer *serialize_response(uint64_t channel_id, MessageType type, uint32_t response_id,
- Error *err, Object arg, msgpack_sbuffer *sbuffer)
+static WBuffer *serialize_response(uint64_t channel_id, MsgpackRpcRequestHandler handler,
+ MessageType type, uint32_t response_id, Error *err, Object arg,
+ msgpack_sbuffer *sbuffer)
{
msgpack_packer pac;
msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
if (ERROR_SET(err) && type == kMessageTypeNotification) {
- Array args = ARRAY_DICT_INIT;
- ADD(args, INTEGER_OBJ(err->type));
- ADD(args, STRING_OBJ(cstr_to_string(err->msg)));
- msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"),
- args, &pac);
- api_free_array(args);
+ if (handler.fn == handle_nvim_paste) {
+ // TODO(bfredl): this is pretty much ad-hoc. maybe TUI and UI:s should be
+ // allowed to ask nvim to just scream directly in the users face
+ // instead of sending nvim_error_event, in general.
+ semsg("paste: %s", err->msg);
+ api_clear_error(err);
+ } else {
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, INTEGER_OBJ(err->type));
+ ADD(args, STRING_OBJ(cstr_to_string(err->msg)));
+ msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"),
+ args, &pac);
+ api_free_array(args);
+ }
} else {
msgpack_rpc_serialize_response(response_id, err, arg, &pac);
}
diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c
index 897ea1f768..44a16beb48 100644
--- a/src/nvim/msgpack_rpc/unpacker.c
+++ b/src/nvim/msgpack_rpc/unpacker.c
@@ -298,7 +298,7 @@ error:
//
// When method is "grid_line", we furthermore decode a cell at a time like:
//
-// <0>[2, "redraw", <10>[{11}["grid_line", <13>[g, r, c, [<14>[cell], <14>[cell], ...]], ...], <11>[...], ...]]
+// <0>[2, "redraw", <10>[{11}["grid_line", <14>[g, r, c, [<15>[cell], <15>[cell], ...]], ...], <11>[...], ...]]
//
// where [cell] is [char, repeat, attr], where 'repeat' and 'attr' is optional
@@ -318,17 +318,19 @@ bool unpacker_advance(Unpacker *p)
}
}
- if (p->state >= 10 && p->state != 12) {
+ if (p->state >= 10 && p->state != 13) {
if (!unpacker_parse_redraw(p)) {
return false;
}
- if (p->state == 14) {
+ if (p->state == 15) {
// grid_line event already unpacked
goto done;
} else {
+ assert(p->state == 12);
// unpack other ui events using mpack_parse()
p->arena = (Arena)ARENA_EMPTY;
+ p->state = 13;
}
}
@@ -355,11 +357,11 @@ done:
case 2:
p->state = 0;
return true;
- case 12:
- case 14:
+ case 13:
+ case 15:
p->ncalls--;
if (p->ncalls > 0) {
- p->state = (p->state == 14) ? 13 : 12;
+ p->state = (p->state == 15) ? 14 : 12;
} else if (p->nevents > 0) {
p->state = 11;
} else {
@@ -428,14 +430,14 @@ redo:
}
return true;
} else {
- p->state = 13;
+ p->state = 14;
p->arena = (Arena)ARENA_EMPTY;
p->grid_line_event = arena_alloc(&p->arena, sizeof *p->grid_line_event, true);
g = p->grid_line_event;
}
FALLTHROUGH;
- case 13:
+ case 14:
NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
int eventarrsize = (int)tok.length;
if (eventarrsize != 4) {
@@ -456,10 +458,10 @@ redo:
p->read_ptr = data;
p->read_size = size;
- p->state = 14;
+ p->state = 15;
FALLTHROUGH;
- case 14:
+ case 15:
assert(g->icell < g->ncells);
NEXT_TYPE(tok, MPACK_TOKEN_ARRAY);
@@ -513,6 +515,9 @@ redo:
}
goto redo;
+ case 12:
+ return true;
+
default:
abort();
}
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index ca1f7c25d7..c6066597f0 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -220,17 +220,11 @@ static void tinput_wait_enqueue(void **argv)
const size_t len = rbuffer_size(input->key_buffer);
String keys = { .data = xmallocz(len), .size = len };
rbuffer_read(input->key_buffer, keys.data, len);
- if (ui_client_channel_id) {
- Array args = ARRAY_DICT_INIT;
- ADD(args, STRING_OBJ(keys)); // 'data'
- ADD(args, BOOLEAN_OBJ(true)); // 'crlf'
- ADD(args, INTEGER_OBJ(input->paste)); // 'phase'
- rpc_send_event(ui_client_channel_id, "nvim_paste", args);
- } else {
- // TODO
- // multiqueue_put(main_loop.events, tinput_paste_event, 3,
- // keys.data, keys.size, (intptr_t)input->paste);
- }
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, STRING_OBJ(keys)); // 'data'
+ ADD(args, BOOLEAN_OBJ(true)); // 'crlf'
+ ADD(args, INTEGER_OBJ(input->paste)); // 'phase'
+ rpc_send_event(ui_client_channel_id, "nvim_paste", args);
if (input->paste == 1) {
// Paste phase: "continue"
input->paste = 2;
@@ -239,39 +233,22 @@ static void tinput_wait_enqueue(void **argv)
} else { // enqueue input for the main thread or Nvim server
RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) {
const String keys = { .data = buf, .size = len };
- size_t consumed;</