Merge #8247 'server: introduce --listen'

This commit is contained in:
Justin M. Keyes
2018-04-11 03:29:18 +02:00
committed by GitHub
14 changed files with 168 additions and 209 deletions

View File

@@ -14403,8 +14403,11 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (argvars[0].vval.v_string) {
server_stop((char *) argvars[0].vval.v_string);
bool rv = server_stop((char *)argvars[0].vval.v_string);
rettv->vval.v_number = (rv ? 1 : 0);
}
}

View File

@@ -6975,12 +6975,10 @@ do_exedit (
ex_no_reprint = TRUE;
}
/*
* ":gui" and ":gvim" when there is no GUI.
*/
/// ":gui" and ":gvim" when there is no GUI.
static void ex_nogui(exarg_T *eap)
{
eap->errmsg = e_nogvim;
eap->errmsg = (char_u *)N_("E25: Nvim does not have a built-in GUI");
}

View File

@@ -1070,7 +1070,6 @@ EXTERN char_u e_nesting[] INIT(= N_("E22: Scripts nested too deep"));
EXTERN char_u e_noalt[] INIT(= N_("E23: No alternate file"));
EXTERN char_u e_noabbr[] INIT(= N_("E24: No such abbreviation"));
EXTERN char_u e_nobang[] INIT(= N_("E477: No ! allowed"));
EXTERN char_u e_nogvim[] INIT(= N_("E25: Nvim does not have a built-in GUI"));
EXTERN char_u e_nogroup[] INIT(= N_("E28: No such highlight group name: %s"));
EXTERN char_u e_noinstext[] INIT(= N_("E29: No inserted text yet"));
EXTERN char_u e_nolastcmd[] INIT(= N_("E30: No previous command line"));

View File

@@ -72,30 +72,30 @@
# include "nvim/os/pty_process_unix.h"
#endif
/* Maximum number of commands from + or -c arguments. */
// Maximum number of commands from + or -c arguments.
#define MAX_ARG_CMDS 10
/* values for "window_layout" */
#define WIN_HOR 1 /* "-o" horizontally split windows */
#define WIN_VER 2 /* "-O" vertically split windows */
#define WIN_TABS 3 /* "-p" windows on tab pages */
// values for "window_layout"
#define WIN_HOR 1 // "-o" horizontally split windows
#define WIN_VER 2 // "-O" vertically split windows
#define WIN_TABS 3 // "-p" windows on tab pages
/* Struct for various parameters passed between main() and other functions. */
// Struct for various parameters passed between main() and other functions.
typedef struct {
int argc;
char **argv;
char *use_vimrc; // vimrc from -u argument
int n_commands; /* no. of commands from + or -c */
int n_commands; // no. of commands from + or -c
char *commands[MAX_ARG_CMDS]; // commands from + or -c arg
char_u cmds_tofree[MAX_ARG_CMDS]; /* commands that need free() */
int n_pre_commands; /* no. of commands from --cmd */
char_u cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
int n_pre_commands; // no. of commands from --cmd
char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
int edit_type; /* type of editing to do */
char_u *tagname; /* tag from -t argument */
char_u *use_ef; /* 'errorfile' from -q argument */
int edit_type; // type of editing to do
char_u *tagname; // tag from -t argument
char_u *use_ef; // 'errorfile' from -q argument
int want_full_screen;
bool input_isatty; // stdin is a terminal
@@ -103,13 +103,15 @@ typedef struct {
bool err_isatty; // stderr is a terminal
int no_swap_file; // "-n" argument used
int use_debug_break_level;
int window_count; /* number of windows to use */
int window_layout; /* 0, WIN_HOR, WIN_VER or WIN_TABS */
int window_count; // number of windows to use
int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS
#if !defined(UNIX)
int literal; /* don't expand file names */
int literal; // don't expand file names
#endif
int diff_mode; /* start with 'diff' set */
int diff_mode; // start with 'diff' set
char *listen_addr; // --listen {address}
} mparm_T;
/* Values for edit_type. */
@@ -150,7 +152,6 @@ void event_init(void)
signal_init();
// finish mspgack-rpc initialization
channel_init();
server_init();
terminal_init();
}
@@ -241,9 +242,8 @@ int main(int argc, char **argv)
char_u *cwd = NULL; // current workding dir on startup
time_init();
/* Many variables are in "params" so that we can pass them to invoked
* functions without a lot of arguments. "argc" and "argv" are also
* copied, so that they can be changed. */
// Many variables are in `params` so that we can pass them around easily.
// `argc` and `argv` are also copied, so that they can be changed.
init_params(&params, argc, argv);
init_startuptime(&params);
@@ -254,11 +254,10 @@ int main(int argc, char **argv)
check_and_set_isatty(&params);
event_init();
/*
* Process the command line arguments. File names are put in the global
* argument list "global_alist".
*/
// Process the command line arguments. File names are put in the global
// argument list "global_alist".
command_line_scan(&params);
server_init(params.listen_addr);
if (GARGCOUNT > 0) {
fname = get_fname(&params, cwd);
@@ -819,6 +818,9 @@ static void command_line_scan(mparm_T *parmp)
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
abort();
}
} else if (STRNICMP(argv[0] + argv_idx, "listen", 6) == 0) {
want_argument = true;
argv_idx += 6;
} else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
#if !defined(UNIX)
parmp->literal = TRUE;
@@ -864,10 +866,6 @@ static void command_line_scan(mparm_T *parmp)
case 'f': /* "-f" GUI: run in foreground. */
break;
case 'g': /* "-g" start GUI */
main_start_gui();
break;
case 'F': { // "-F" start in Farsi mode: rl + fkmap set.
p_fkmap = true;
set_option_value("rl", 1L, NULL, 0);
@@ -906,18 +904,8 @@ static void command_line_scan(mparm_T *parmp)
parmp->no_swap_file = TRUE;
break;
case 'p': /* "-p[N]" open N tab pages */
#ifdef TARGET_API_MAC_OSX
/* For some reason on MacOS X, an argument like:
-psn_0_10223617 is passed in when invoke from Finder
or with the 'open' command */
if (argv[0][argv_idx] == 's') {
argv_idx = -1; /* bypass full -psn */
main_start_gui();
break;
}
#endif
/* default is 0: open window for each file */
case 'p': // "-p[N]" open N tab pages
// default is 0: open window for each file
parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
parmp->window_layout = WIN_TABS;
break;
@@ -1030,15 +1018,12 @@ static void command_line_scan(mparm_T *parmp)
mainerr(err_opt_unknown, argv[0]);
}
/*
* Handle option arguments with argument.
*/
// Handle option arguments with argument.
if (want_argument) {
/*
* Check for garbage immediately after the option letter.
*/
if (argv[0][argv_idx] != NUL)
// Check for garbage immediately after the option letter.
if (argv[0][argv_idx] != NUL) {
mainerr(err_opt_garbage, argv[0]);
}
--argc;
if (argc < 1 && c != 'S') /* -S has an optional argument */
@@ -1077,13 +1062,17 @@ static void command_line_scan(mparm_T *parmp)
break;
case '-':
if (argv[-1][2] == 'c') {
/* "--cmd {command}" execute command */
if (parmp->n_pre_commands >= MAX_ARG_CMDS)
if (strequal(argv[-1], "--cmd")) {
// "--cmd {command}" execute command
if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
mainerr(err_extra_cmd, NULL);
}
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
} else if (strequal(argv[-1], "--listen")) {
// "--listen {address}"
parmp->listen_addr = argv[0];
}
/* "--startuptime <file>" already handled */
// "--startuptime <file>" already handled
break;
case 'q': /* "-q {errorfile}" QuickFix mode */
@@ -1224,11 +1213,10 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
paramp->want_full_screen = true;
paramp->use_debug_break_level = -1;
paramp->window_count = -1;
paramp->listen_addr = NULL;
}
/*
* Initialize global startuptime file if "--startuptime" passed as an argument.
*/
/// Initialize global startuptime file if "--startuptime" passed as an argument.
static void init_startuptime(mparm_T *paramp)
{
for (int i = 1; i < paramp->argc; i++) {
@@ -1834,17 +1822,6 @@ static void source_startup_scripts(const mparm_T *const parmp)
TIME_MSG("sourcing vimrc file(s)");
}
/*
* Setup to start using the GUI. Exit with an error when not available.
*/
static void main_start_gui(void)
{
mch_errmsg(_(e_nogvim));
mch_errmsg("\n");
mch_exit(2);
}
/// Get an environment variable, and execute it as Ex commands.
///
/// @param env environment variable to execute
@@ -1968,6 +1945,7 @@ static void usage(void)
mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
mch_msg(_(" --headless Don't start a user interface\n"));
mch_msg(_(" --listen <address> Start RPC server at this address\n"));
#if !defined(UNIX)
mch_msg(_(" --literal Don't expand wildcards\n"));
#endif

View File

@@ -32,26 +32,27 @@ static garray_T watchers = GA_EMPTY_INIT_VALUE;
#endif
/// Initializes the module
bool server_init(void)
bool server_init(const char *listen_addr)
{
ga_init(&watchers, sizeof(SocketWatcher *), 1);
bool must_free = false;
const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
if (listen_address == NULL) {
must_free = true;
listen_address = server_address_new();
// $NVIM_LISTEN_ADDRESS
const char *env_addr = os_getenv(LISTEN_ADDRESS_ENV_VAR);
int rv = listen_addr == NULL ? 1 : server_start(listen_addr);
if (0 != rv) {
rv = env_addr == NULL ? 1 : server_start(env_addr);
if (0 != rv) {
listen_addr = server_address_new();
if (listen_addr == NULL) {
return false;
}
rv = server_start(listen_addr);
xfree((char *)listen_addr);
}
}
if (!listen_address) {
return false;
}
bool ok = (server_start(listen_address) == 0);
if (must_free) {
xfree((char *) listen_address);
}
return ok;
return rv == 0;
}
/// Teardown a single server
@@ -120,8 +121,8 @@ bool server_owns_pipe_address(const char *path)
/// @param endpoint Address of the server. Either a 'ip:[port]' string or an
/// arbitrary identifier (trimmed to 256 bytes) for the Unix
/// socket or named pipe.
/// @returns 0 on success, 1 on a regular error, and negative errno
/// on failure to bind or listen.
/// @returns 0: success, 1: validation error, 2: already listening,
/// -errno: failed to bind or listen.
int server_start(const char *endpoint)
{
if (endpoint == NULL || endpoint[0] == '\0') {
@@ -145,7 +146,7 @@ int server_start(const char *endpoint)
uv_freeaddrinfo(watcher->uv.tcp.addrinfo);
}
socket_watcher_close(watcher, free_server);
return 1;
return 2;
}
}
@@ -177,7 +178,7 @@ int server_start(const char *endpoint)
/// Stops listening on the address specified by `endpoint`.
///
/// @param endpoint Address of the server.
void server_stop(char *endpoint)
bool server_stop(char *endpoint)
{
SocketWatcher *watcher;
bool watcher_found = false;
@@ -196,8 +197,8 @@ void server_stop(char *endpoint)
}
if (!watcher_found) {
ELOG("Not listening on %s", addr);
return;
WLOG("Not listening on %s", addr);
return false;
}
// Unset $NVIM_LISTEN_ADDRESS if it is the stopped address.
@@ -219,6 +220,8 @@ void server_stop(char *endpoint)
if (STRCMP(addr, get_vim_var_str(VV_SEND_SERVER)) == 0) {
set_vservername(&watchers);
}
return true;
}
/// Returns an allocated array of server addresses.