aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/main.c')
-rw-r--r--src/nvim/main.c227
1 files changed, 212 insertions, 15 deletions
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 921bc883cf..6ea1cb0875 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -9,25 +9,29 @@
#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"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
+#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/iconv.h"
#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>
@@ -39,7 +43,6 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/misc1.h"
#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
@@ -111,7 +114,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);
@@ -155,10 +157,11 @@ bool event_teardown(void)
void early_init(mparm_T *paramp)
{
env_init();
- fs_init();
+ cmdline_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
@@ -231,6 +234,10 @@ int main(int argc, char **argv)
// `argc` and `argv` are also copied, so that they can be changed.
init_params(&params, argc, argv);
+ // Since os_open is called during the init_startuptime, we need to call
+ // fs_init before it.
+ fs_init();
+
init_startuptime(&params);
// Need to find "--clean" before actually parsing arguments.
@@ -250,12 +257,12 @@ int main(int argc, char **argv)
// Check if we have an interactive window.
check_and_set_isatty(&params);
- nlua_init();
-
// Process the command line arguments. File names are put in the global
// argument list "global_alist".
command_line_scan(&params);
+ nlua_init();
+
if (embedded_mode) {
const char *err;
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
@@ -264,6 +271,9 @@ int main(int argc, char **argv)
}
server_init(params.listen_addr);
+ if (params.remote) {
+ remote_request(&params, params.remote, params.server_addr, argc, argv);
+ }
if (GARGCOUNT > 0) {
fname = get_fname(&params, cwd);
@@ -336,15 +346,23 @@ 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");
init_default_autocmds();
TIME_MSG("init default autocommands");
+ bool vimrc_none = params.use_vimrc != NULL && strequal(params.use_vimrc, "NONE");
+
// Reset 'loadplugins' for "-u NONE" before "--cmd" arguments.
// Allows for setting 'loadplugins' there.
- if (params.use_vimrc != NULL && strequal(params.use_vimrc, "NONE")) {
+ if (vimrc_none) {
// When using --clean we still want to load plugins
p_lpl = params.clean;
}
@@ -352,14 +370,23 @@ int main(int argc, char **argv)
// Execute --cmd arguments.
exe_pre_commands(&params);
+ 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).
+ filetype_plugin_enable();
+ }
+
// Source startup scripts.
source_startup_scripts(&params);
// If using the runtime (-u is not NONE), enable syntax & filetype plugins.
- if (params.use_vimrc == NULL || !strequal(params.use_vimrc, "NONE")) {
- // Does ":filetype plugin indent on".
+ if (!vimrc_none || params.clean) {
+ // Sources filetype.lua and filetype.vim unless the user explicitly disabled it with :filetype
+ // off.
filetype_maybe_enable();
- // Sources syntax/syntax.vim, which calls `:filetype on`.
+ // Sources syntax/syntax.vim. We do this *after* the user startup scripts so that users can
+ // disable syntax highlighting with `:syntax off` if they wish.
syn_maybe_enable();
}
@@ -696,6 +723,50 @@ void getout(int exitval)
os_exit(exitval);
}
+/// Preserve files and exit.
+/// @note IObuff must contain a message.
+/// @note This may be called from deadly_signal() in a signal handler, avoid
+/// unsafe functions, such as allocating memory.
+void preserve_exit(void)
+ FUNC_ATTR_NORETURN
+{
+ // 'true' when we are sure to exit, e.g., after a deadly signal
+ static bool really_exiting = false;
+
+ // Prevent repeated calls into this method.
+ if (really_exiting) {
+ if (input_global_fd() >= 0) {
+ // normalize stream (#2598)
+ stream_set_blocking(input_global_fd(), true);
+ }
+ exit(2);
+ }
+
+ really_exiting = true;
+ // Ignore SIGHUP while we are already exiting. #9274
+ signal_reject_deadly();
+ mch_errmsg(IObuff);
+ mch_errmsg("\n");
+ ui_flush();
+
+ ml_close_notmod(); // close all not-modified buffers
+
+ FOR_ALL_BUFFERS(buf) {
+ if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
+ mch_errmsg("Vim: preserving files...\r\n");
+ ui_flush();
+ ml_sync_all(false, false, true); // preserve all swap files
+ break;
+ }
+ }
+
+ ml_close_all(false); // close all memfiles, without deleting
+
+ mch_errmsg("Vim: Finished.\r\n");
+
+ getout(1);
+}
+
/// Gets the integer value of a numeric command line argument if given,
/// such as '-o10'.
///
@@ -744,6 +815,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)
@@ -765,7 +944,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--;
@@ -787,7 +965,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) {
@@ -810,6 +988,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);
@@ -848,6 +1028,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) {
@@ -860,6 +1045,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]);
@@ -1077,6 +1264,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;
@@ -1231,6 +1421,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.
@@ -1506,7 +1698,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
// When w_arg_idx is -1 remove the window (see create_windows()).
if (curwin->w_arg_idx == -1) {
- win_close(curwin, true);
+ win_close(curwin, true, false);
advance = false;
}
@@ -1518,7 +1710,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
// When w_arg_idx is -1 remove the window (see create_windows()).
if (curwin->w_arg_idx == -1) {
arg_idx++;
- win_close(curwin, true);
+ win_close(curwin, true, false);
advance = false;
continue;
}
@@ -1565,7 +1757,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
did_emsg = FALSE; // avoid hit-enter prompt
getout(1);
}
- win_close(curwin, true);
+ win_close(curwin, true, false);
advance = false;
}
if (arg_idx == GARGCOUNT - 1) {
@@ -1909,6 +2101,7 @@ static bool file_owned(const char *fname)
/// @param errstr string containing an error message
/// @param str string to append to the primary error message, or NULL
static void mainerr(const char *errstr, const char *str)
+ FUNC_ATTR_NORETURN
{
char *prgname = (char *)path_tail((char_u *)argv0);
@@ -1932,6 +2125,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');
@@ -1979,6 +2174,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"));
}