diff options
Diffstat (limited to 'src/nvim/main.c')
-rw-r--r-- | src/nvim/main.c | 157 |
1 files changed, 148 insertions, 9 deletions
diff --git a/src/nvim/main.c b/src/nvim/main.c index 8991ae7f00..d67b47e82c 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -9,11 +9,12 @@ #include <string.h> #include "nvim/ascii.h" -#include "nvim/aucmd.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/decoration.h" +#include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" @@ -28,6 +29,7 @@ #include "nvim/if_cscope.h" #include "nvim/lua/executor.h" #include "nvim/main.h" +#include "nvim/ui_client.h" #include "nvim/vim.h" #ifdef HAVE_LOCALE_H # include <locale.h> @@ -110,7 +112,6 @@ static const char *err_too_many_args = N_("Too many edit arguments"); static const char *err_extra_cmd = N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"); - void event_init(void) { loop_init(&main_loop, NULL); @@ -154,10 +155,10 @@ bool event_teardown(void) void early_init(mparm_T *paramp) { env_init(); - fs_init(); eval_init(); // init global variables init_path(argv0 ? argv0 : "nvim"); init_normal_cmds(); // Init the table of Normal mode commands. + runtime_init(); highlight_init(); #ifdef WIN32 @@ -230,6 +231,10 @@ int main(int argc, char **argv) // `argc` and `argv` are also copied, so that they can be changed. init_params(¶ms, argc, argv); + // Since os_open is called during the init_startuptime, we need to call + // fs_init before it. + fs_init(); + init_startuptime(¶ms); // Need to find "--clean" before actually parsing arguments. @@ -249,12 +254,12 @@ int main(int argc, char **argv) // Check if we have an interactive window. check_and_set_isatty(¶ms); - nlua_init(); - // Process the command line arguments. File names are put in the global // argument list "global_alist". command_line_scan(¶ms); + nlua_init(); + if (embedded_mode) { const char *err; if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) { @@ -263,6 +268,9 @@ int main(int argc, char **argv) } server_init(params.listen_addr); + if (params.remote) { + remote_request(¶ms, params.remote, params.server_addr, argc, argv); + } if (GARGCOUNT > 0) { fname = get_fname(¶ms, cwd); @@ -335,6 +343,12 @@ int main(int argc, char **argv) TIME_MSG("init screen for UI"); } + if (ui_client_channel_id) { + ui_client_init(ui_client_channel_id); + ui_client_execute(ui_client_channel_id); + abort(); // unreachable + } + init_default_mappings(); // Default mappings. TIME_MSG("init default mappings"); @@ -353,7 +367,7 @@ int main(int argc, char **argv) // Execute --cmd arguments. exe_pre_commands(¶ms); - if (!vimrc_none) { + if (!vimrc_none || params.clean) { // Sources ftplugin.vim and indent.vim. We do this *before* the user startup scripts to ensure // ftplugins run before FileType autocommands defined in the init file (which allows those // autocommands to overwrite settings from ftplugins). @@ -364,7 +378,7 @@ int main(int argc, char **argv) source_startup_scripts(¶ms); // If using the runtime (-u is not NONE), enable syntax & filetype plugins. - if (!vimrc_none) { + if (!vimrc_none || params.clean) { // Sources filetype.lua and filetype.vim unless the user explicitly disabled it with :filetype // off. filetype_maybe_enable(); @@ -798,6 +812,114 @@ static void init_locale(void) } #endif + +static uint64_t server_connect(char *server_addr, const char **errmsg) +{ + if (server_addr == NULL) { + *errmsg = "no address specified"; + return 0; + } + CallbackReader on_data = CALLBACK_READER_INIT; + const char *error = NULL; + bool is_tcp = strrchr(server_addr, ':') ? true : false; + // connected to channel + uint64_t chan = channel_connect(is_tcp, server_addr, true, on_data, 50, &error); + if (error) { + *errmsg = error; + return 0; + } + return chan; +} + +/// Handle remote subcommands +static void remote_request(mparm_T *params, int remote_args, + char *server_addr, int argc, char **argv) +{ + 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 (!chan) { + emsg(connect_error); + exit(1); + } + + ui_client_channel_id = chan; + return; + } + + Array args = ARRAY_DICT_INIT; + String arg_s; + for (int t_argc = remote_args; t_argc < argc; t_argc++) { + arg_s = cstr_to_string(argv[t_argc]); + ADD(args, STRING_OBJ(arg_s)); + } + + Error err = ERROR_INIT; + Array a = ARRAY_DICT_INIT; + ADD(a, INTEGER_OBJ((int)chan)); + ADD(a, CSTR_TO_OBJ(server_addr)); + ADD(a, CSTR_TO_OBJ(connect_error)); + ADD(a, ARRAY_OBJ(args)); + String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)"); + Object o = nlua_exec(s, a, &err); + api_free_array(a); + if (ERROR_SET(&err)) { + mch_errmsg(err.msg); + mch_errmsg("\n"); + os_exit(2); + } + + if (o.type == kObjectTypeDictionary) { + rvobj.data.dictionary = o.data.dictionary; + } else { + mch_errmsg("vim._cs_remote returned unexpected value\n"); + os_exit(2); + } + + TriState should_exit = kNone; + TriState tabbed = kNone; + + for (size_t i = 0; i < rvobj.data.dictionary.size ; i++) { + if (strcmp(rvobj.data.dictionary.items[i].key.data, "errmsg") == 0) { + if (rvobj.data.dictionary.items[i].value.type != kObjectTypeString) { + mch_errmsg("vim._cs_remote returned an unexpected type for 'errmsg'\n"); + os_exit(2); + } + mch_errmsg(rvobj.data.dictionary.items[i].value.data.string.data); + mch_errmsg("\n"); + os_exit(2); + } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "tabbed") == 0) { + if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) { + mch_errmsg("vim._cs_remote returned an unexpected type for 'tabbed'\n"); + os_exit(2); + } + tabbed = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse; + } else if (strcmp(rvobj.data.dictionary.items[i].key.data, "should_exit") == 0) { + if (rvobj.data.dictionary.items[i].value.type != kObjectTypeBoolean) { + mch_errmsg("vim._cs_remote returned an unexpected type for 'should_exit'\n"); + os_exit(2); + } + should_exit = rvobj.data.dictionary.items[i].value.data.boolean ? kTrue : kFalse; + } + } + if (should_exit == kNone || tabbed == kNone) { + mch_errmsg("vim._cs_remote didn't return a value for should_exit or tabbed, bailing\n"); + os_exit(2); + } + api_free_object(o); + + if (should_exit == kTrue) { + os_exit(0); + } + if (tabbed == kTrue) { + params->window_count = argc - remote_args - 1; + params->window_layout = WIN_TABS; + } +} + + /// Decides whether text (as opposed to commands) will be read from stdin. /// @see EDIT_STDIN static bool edit_stdin(bool explicit, mparm_T *parmp) @@ -819,7 +941,6 @@ static void command_line_scan(mparm_T *parmp) bool had_stdin_file = false; // found explicit "-" argument bool had_minmin = false; // found "--" argument int want_argument; // option argument with argument - int c; long n; argc--; @@ -841,7 +962,7 @@ static void command_line_scan(mparm_T *parmp) // Optional argument. } else if (argv[0][0] == '-' && !had_minmin) { want_argument = false; - c = argv[0][argv_idx++]; + char c = argv[0][argv_idx++]; switch (c) { case NUL: // "nvim -" read from stdin if (exmode_active) { @@ -864,6 +985,8 @@ static void command_line_scan(mparm_T *parmp) // "--version" give version message // "--noplugin[s]" skip plugins // "--cmd <cmd>" execute cmd before vimrc + // "--remote" execute commands remotey on a server + // "--server" name of vim server to send remote commands to if (STRICMP(argv[0] + argv_idx, "help") == 0) { usage(); os_exit(0); @@ -902,6 +1025,11 @@ static void command_line_scan(mparm_T *parmp) argv_idx += 6; } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) { // Do nothing: file args are always literal. #7679 + } else if (STRNICMP(argv[0] + argv_idx, "remote", 6) == 0) { + parmp->remote = parmp->argc - argc; + } else if (STRNICMP(argv[0] + argv_idx, "server", 6) == 0) { + want_argument = true; + argv_idx += 6; } else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) { p_lpl = false; } else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) { @@ -914,6 +1042,8 @@ static void command_line_scan(mparm_T *parmp) parmp->use_vimrc = "NONE"; parmp->clean = true; set_option_value("shadafile", 0L, "NONE", 0); + } else if (STRNICMP(argv[0] + argv_idx, "luamod-dev", 9) == 0) { + nlua_disable_preload = true; } else { if (argv[0][argv_idx]) { mainerr(err_opt_unknown, argv[0]); @@ -1131,6 +1261,9 @@ static void command_line_scan(mparm_T *parmp) } else if (strequal(argv[-1], "--listen")) { // "--listen {address}" parmp->listen_addr = argv[0]; + } else if (strequal(argv[-1], "--server")) { + // "--server {address}" + parmp->server_addr = argv[0]; } // "--startuptime <file>" already handled break; @@ -1285,6 +1418,8 @@ static void init_params(mparm_T *paramp, int argc, char **argv) paramp->use_debug_break_level = -1; paramp->window_count = -1; paramp->listen_addr = NULL; + paramp->server_addr = NULL; + paramp->remote = 0; } /// Initialize global startuptime file if "--startuptime" passed as an argument. @@ -1986,6 +2121,8 @@ static void mainerr(const char *errstr, const char *str) /// Prints version information for "nvim -v" or "nvim --version". static void version(void) { + // TODO(bfred): not like this? + nlua_init(); info_message = true; // use mch_msg(), not mch_errmsg() list_version(); msg_putchar('\n'); @@ -2033,6 +2170,8 @@ static void usage(void) mch_msg(_(" --headless Don't start a user interface\n")); mch_msg(_(" --listen <address> Serve RPC API from this address\n")); mch_msg(_(" --noplugin Don't load plugins\n")); + mch_msg(_(" --remote[-subcommand] Execute commands remotely on a server\n")); + mch_msg(_(" --server <address> Specify RPC server to send commands to\n")); mch_msg(_(" --startuptime <file> Write startup timing messages to <file>\n")); mch_msg(_("\nSee \":help startup-options\" for all options.\n")); } |