Merge #8247 'server: introduce --listen'
This commit is contained in:
commit
f96d99ad11
40
man/nvim.1
40
man/nvim.1
|
@ -25,7 +25,7 @@ To enter commands in
|
|||
type a colon
|
||||
.Pq Sq \&:
|
||||
which is also used in this manual to denote commands.
|
||||
For more information, consult the on-line help system with the
|
||||
For more information, consult the online help system with the
|
||||
.Ic :help
|
||||
command.
|
||||
.Bl -tag -width Fl
|
||||
|
@ -329,6 +329,9 @@ Implies
|
|||
.Fl -headless .
|
||||
.It Fl -headless
|
||||
Do not start a user interface.
|
||||
.Fl -listen .
|
||||
.It Fl -listen Ar address
|
||||
Start RPC server on this pipe or TCP socket.
|
||||
.It Fl h , -help
|
||||
Print usage information and exit.
|
||||
.It Fl v , -version
|
||||
|
@ -337,12 +340,12 @@ Print version information and exit.
|
|||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Fl
|
||||
.It Ev VIM
|
||||
Used to locate various user files, such as the user's init.vim.
|
||||
Used to locate various user files, such as init.vim.
|
||||
.It Ev VIMRUNTIME
|
||||
Used to locate run time files, such as on-line documentation and
|
||||
Used to locate runtime files, such as online documentation and
|
||||
syntax highlighting definitions.
|
||||
.It Ev XDG_CONFIG_HOME
|
||||
Path to use for the user-local configuration directory, see
|
||||
Path to the user-local configuration directory, see
|
||||
.Sx FILES .
|
||||
Defaults to
|
||||
.Pa ~/.config
|
||||
|
@ -356,7 +359,7 @@ Defaults to
|
|||
.Pa ~/.local/share
|
||||
if not set.
|
||||
.It Ev VIMINIT
|
||||
A string of Ex commands to be executed at startup.
|
||||
Ex commands to be executed at startup.
|
||||
For example, the command to quit is
|
||||
.Ic :q ,
|
||||
so to have
|
||||
|
@ -375,41 +378,32 @@ command.
|
|||
.Sh FILES
|
||||
.Bl -tag -width "~/.config/nvim/init.vim"
|
||||
.It Pa ~/.config/nvim/init.vim
|
||||
The user-local
|
||||
User-local
|
||||
.Nm
|
||||
configuration file.
|
||||
See
|
||||
.Ev XDG_CONFIG_HOME
|
||||
above.
|
||||
.It Pa ~/.config/nvim
|
||||
The user-local
|
||||
User-local
|
||||
.Nm
|
||||
configuration directory.
|
||||
See
|
||||
.Ev XDG_CONFIG_HOME
|
||||
above.
|
||||
See also
|
||||
.Ev XDG_CONFIG_HOME .
|
||||
.It Pa $VIM/sysinit.vim
|
||||
The system-global
|
||||
System-global
|
||||
.Nm
|
||||
configuration file.
|
||||
.It Pa /usr/local/share/nvim
|
||||
The system-global
|
||||
System-global
|
||||
.Nm
|
||||
runtime directory.
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.Nm
|
||||
was started by
|
||||
.An Thiago de Arruda ,
|
||||
with a lot of help from others.
|
||||
.Pp
|
||||
Nvim was started by
|
||||
.An Thiago de Arruda .
|
||||
Most of Vim was written by
|
||||
.An -nosplit
|
||||
.An Bram Moolenaar ,
|
||||
with a lot of help from others.
|
||||
.An Bram Moolenaar .
|
||||
See
|
||||
.Ic :help credits .
|
||||
.Pp
|
||||
Vim is based on Stevie, worked on by
|
||||
.An Tim Thompson ,
|
||||
.An Tony Andrews ,
|
||||
|
|
|
@ -22,6 +22,10 @@ Commands ~
|
|||
*:wv*
|
||||
*:wviminfo* Deprecated alias to |:wshada| command.
|
||||
|
||||
Environment Variables ~
|
||||
*$NVIM_LISTEN_ADDRESS* Deprecated in favor of |--listen|. If both are given,
|
||||
$NVIM_LISTEN_ADDRESS is ignored.
|
||||
|
||||
Events ~
|
||||
*EncodingChanged* Never fired; 'encoding' is always "utf-8".
|
||||
*FileEncoding* Never fired; equivalent to |EncodingChanged|.
|
||||
|
|
|
@ -1788,9 +1788,9 @@ v:scrollstart String describing the script or function that caused the
|
|||
hit-enter prompt.
|
||||
|
||||
*v:servername* *servername-variable*
|
||||
*$NVIM_LISTEN_ADDRESS*
|
||||
v:servername Default Nvim server address. Equivalent to
|
||||
|$NVIM_LISTEN_ADDRESS| on startup. |serverstop()|
|
||||
v:servername Primary listen-address of the current Nvim instance, the first
|
||||
item returned by |serverlist()|. Can be set by |--listen| or
|
||||
|$NVIM_LISTEN_ADDRESS| at startup. |serverstart()| |serverstop()|
|
||||
Read-only.
|
||||
|
||||
|
||||
|
@ -6638,15 +6638,11 @@ server2client({clientid}, {string}) *server2client()*
|
|||
:echo server2client(expand("<client>"), "HELLO")
|
||||
<
|
||||
serverlist() *serverlist()*
|
||||
Returns a list of available server names in a list.
|
||||
When there are no servers an empty string is returned.
|
||||
Returns a list of server addresses, or empty if all servers
|
||||
were stopped. |serverstart()| |serverstop()|
|
||||
Example: >
|
||||
:echo serverlist()
|
||||
< {Nvim} *--serverlist*
|
||||
The Vim command-line option `--serverlist` was removed from
|
||||
Nvim, but it can be imitated: >
|
||||
nvim --cmd "echo serverlist()" --cmd "q"
|
||||
<
|
||||
|
||||
serverstart([{address}]) *serverstart()*
|
||||
Opens a socket or named pipe at {address} and listens for
|
||||
|RPC| messages. Clients can send |API| commands to the address
|
||||
|
@ -6674,13 +6670,9 @@ serverstart([{address}]) *serverstart()*
|
|||
|
||||
< |$NVIM_LISTEN_ADDRESS| is set to {address} if not already set.
|
||||
|
||||
*--servername*
|
||||
The Vim command-line option `--servername` can be imitated: >
|
||||
nvim --cmd "let g:server_addr = serverstart('foo')"
|
||||
<
|
||||
serverstop({address}) *serverstop()*
|
||||
Closes the pipe or socket at {address}. Does nothing if
|
||||
{address} is empty or invalid.
|
||||
Closes the pipe or socket at {address}.
|
||||
Returns TRUE if {address} is valid, else FALSE.
|
||||
If |$NVIM_LISTEN_ADDRESS| is stopped it is unset.
|
||||
If |v:servername| is stopped it is set to the next available
|
||||
address returned by |serverlist()|.
|
||||
|
|
|
@ -70,9 +70,8 @@ An rpc socket is automatically created with each instance. The socket
|
|||
location is stored in |v:servername|. By default this is a named pipe
|
||||
with an automatically generated address. See |XXX|.
|
||||
|
||||
To make Nvim listen on a TCP/IP socket instead, set the
|
||||
|$NVIM_LISTEN_ADDRESS| environment variable before starting Nvim: >
|
||||
NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim
|
||||
To make Nvim listen on a TCP/IP socket instead, specify |--listen|: >
|
||||
nvim --listen 127.0.0.1:6666
|
||||
<Also, more sockets and named pipes can be listened on using |serverstart()|.
|
||||
|
||||
Note that localhost TCP sockets are generally less secure than named pipes,
|
||||
|
|
|
@ -355,6 +355,10 @@ argument.
|
|||
instead.
|
||||
See also |silent-mode|, which does start a (limited) UI.
|
||||
|
||||
--listen {addr} *--listen*
|
||||
Start |RPC| server on socket or TCP address {addr}. Sets the
|
||||
primary listen address |v:servername| to {addr}. |serverstart()|
|
||||
|
||||
==============================================================================
|
||||
2. Initialization *initialization* *startup*
|
||||
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
#!/usr/bin/env expect
|
||||
|
||||
if {$argc < 2} {
|
||||
puts "Need commands for running the tests and for starting nvim"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set timeout 60
|
||||
set run_tests [split [lindex $argv 0] " "]
|
||||
set run_nvim [split [lindex $argv 1] " "]
|
||||
|
||||
# don't echo to stdout
|
||||
log_user 0
|
||||
# set NVIM_LISTEN_ADDRESS, so nvim will listen on a known socket
|
||||
set env(NVIM_LISTEN_ADDRESS) "/tmp/nvim-[exec date +%s%N].sock"
|
||||
# start nvim
|
||||
spawn {*}$run_nvim
|
||||
# save the job descriptor
|
||||
set nvim_id $spawn_id
|
||||
# Reset function that can be invoked by test runners to put nvim in a cleaner
|
||||
# state
|
||||
send {
|
||||
:echo "read"."y"
|
||||
}
|
||||
# wait until nvim is ready
|
||||
expect "ready"
|
||||
# run tests
|
||||
spawn {*}$run_tests
|
||||
set tests_id $spawn_id
|
||||
set status 1
|
||||
# listen for test output in the background
|
||||
expect_background {
|
||||
* {
|
||||
# show test output to the user
|
||||
send_user -- $expect_out(buffer)
|
||||
}
|
||||
eof {
|
||||
# collect the exit status code
|
||||
set spawn_id $tests_id
|
||||
catch wait result
|
||||
set status [lindex $result 3]
|
||||
set spawn_id $nvim_id
|
||||
# quit nvim
|
||||
send ":qa!\r"
|
||||
}
|
||||
}
|
||||
# switch back nvim and wait until it exits
|
||||
set spawn_id $nvim_id
|
||||
expect eof
|
||||
exit $status
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
108
src/nvim/main.c
108
src/nvim/main.c
|
@ -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(¶ms, argc, argv);
|
||||
|
||||
init_startuptime(¶ms);
|
||||
|
@ -254,11 +254,10 @@ int main(int argc, char **argv)
|
|||
check_and_set_isatty(¶ms);
|
||||
|
||||
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(¶ms);
|
||||
server_init(params.listen_addr);
|
||||
|
||||
if (GARGCOUNT > 0) {
|
||||
fname = get_fname(¶ms, 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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,31 +1,40 @@
|
|||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
|
||||
local command = helpers.command
|
||||
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
|
||||
local os_name = helpers.os_name
|
||||
local iswin = helpers.iswin
|
||||
local ok = helpers.ok
|
||||
local matches = helpers.matches
|
||||
|
||||
local function clear_serverlist()
|
||||
for _, server in pairs(funcs.serverlist()) do
|
||||
funcs.serverstop(server)
|
||||
end
|
||||
for _, server in pairs(funcs.serverlist()) do
|
||||
funcs.serverstop(server)
|
||||
end
|
||||
end
|
||||
|
||||
describe('serverstart(), serverstop()', function()
|
||||
describe('server', function()
|
||||
before_each(clear)
|
||||
|
||||
it('sets $NVIM_LISTEN_ADDRESS on first invocation', function()
|
||||
it('serverstart() sets $NVIM_LISTEN_ADDRESS on first invocation', function()
|
||||
-- Unset $NVIM_LISTEN_ADDRESS
|
||||
command('let $NVIM_LISTEN_ADDRESS = ""')
|
||||
|
||||
local s = eval('serverstart()')
|
||||
assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
|
||||
eq(s, eval('$NVIM_LISTEN_ADDRESS'))
|
||||
command("call serverstop('"..s.."')")
|
||||
eq(1, eval("serverstop('"..s.."')"))
|
||||
eq('', eval('$NVIM_LISTEN_ADDRESS'))
|
||||
end)
|
||||
|
||||
it('sets v:servername _only_ on nvim startup unless all servers are stopped',
|
||||
it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function()
|
||||
clear({env={NVIM_LISTEN_ADDRESS='.'}})
|
||||
eq('.', eval('$NVIM_LISTEN_ADDRESS'))
|
||||
local servers = funcs.serverlist()
|
||||
eq(1, #servers)
|
||||
ok(string.len(servers[1]) > 4) -- Like /tmp/nvim…/… or \\.\pipe\…
|
||||
end)
|
||||
|
||||
it('sets v:servername at startup or if all servers were stopped',
|
||||
function()
|
||||
local initial_server = meths.get_vvar('servername')
|
||||
assert(initial_server ~= nil and initial_server:len() > 0,
|
||||
|
@ -38,24 +47,23 @@ describe('serverstart(), serverstop()', function()
|
|||
neq(initial_server, s)
|
||||
|
||||
-- serverstop() does _not_ modify v:servername...
|
||||
funcs.serverstop(s)
|
||||
eq(1, funcs.serverstop(s))
|
||||
eq(initial_server, meths.get_vvar('servername'))
|
||||
|
||||
-- ...unless we stop _all_ servers.
|
||||
funcs.serverstop(funcs.serverlist()[1])
|
||||
eq(1, funcs.serverstop(funcs.serverlist()[1]))
|
||||
eq('', meths.get_vvar('servername'))
|
||||
|
||||
-- v:servername will take the next available server.
|
||||
local servername = (os_name() == 'windows'
|
||||
and [[\\.\pipe\Xtest-functional-server-pipe]]
|
||||
or 'Xtest-functional-server-socket')
|
||||
local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]]
|
||||
or 'Xtest-functional-server-socket')
|
||||
funcs.serverstart(servername)
|
||||
eq(servername, meths.get_vvar('servername'))
|
||||
end)
|
||||
|
||||
it('serverstop() ignores invalid input', function()
|
||||
command("call serverstop('')")
|
||||
command("call serverstop('bogus-socket-name')")
|
||||
it('serverstop() returns false for invalid input', function()
|
||||
eq(0, eval("serverstop('')"))
|
||||
eq(0, eval("serverstop('bogus-socket-name')"))
|
||||
end)
|
||||
|
||||
it('parses endpoints correctly', function()
|
||||
|
@ -96,17 +104,13 @@ describe('serverstart(), serverstop()', function()
|
|||
funcs.serverstart('127.0.0.1:65536') -- invalid port
|
||||
eq({}, funcs.serverlist())
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('serverlist()', function()
|
||||
before_each(clear)
|
||||
|
||||
it('returns the list of servers', function()
|
||||
it('serverlist() returns the list of servers', function()
|
||||
-- There should already be at least one server.
|
||||
local n = eval('len(serverlist())')
|
||||
|
||||
-- Add a few
|
||||
local servs = (os_name() == 'windows'
|
||||
-- Add some servers.
|
||||
local servs = (iswin()
|
||||
and { [[\\.\pipe\Xtest-pipe0934]], [[\\.\pipe\Xtest-pipe4324]] }
|
||||
or { [[Xtest-pipe0934]], [[Xtest-pipe4324]] })
|
||||
for _, s in ipairs(servs) do
|
||||
|
@ -120,9 +124,31 @@ describe('serverlist()', function()
|
|||
-- The new servers should be at the end of the list.
|
||||
for i = 1, #servs do
|
||||
eq(servs[i], new_servs[i + n])
|
||||
command("call serverstop('"..servs[i].."')")
|
||||
eq(1, eval("serverstop('"..servs[i].."')"))
|
||||
end
|
||||
-- After serverstop() the servers should NOT be in the list.
|
||||
eq(n, eval('len(serverlist())'))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('startup --listen', function()
|
||||
it('validates', function()
|
||||
clear()
|
||||
|
||||
local cmd = { unpack(helpers.nvim_argv) }
|
||||
table.insert(cmd, '--listen')
|
||||
matches('nvim.*: Argument missing after: "%-%-listen"', funcs.system(cmd))
|
||||
|
||||
cmd = { unpack(helpers.nvim_argv) }
|
||||
table.insert(cmd, '--listen2')
|
||||
matches('nvim.*: Garbage after option argument: "%-%-listen2"', funcs.system(cmd))
|
||||
end)
|
||||
|
||||
it('sets v:servername, overrides $NVIM_LISTEN_ADDRESS', function()
|
||||
local addr = (iswin() and [[\\.\pipe\Xtest-listen-pipe]]
|
||||
or 'Xtest-listen-pipe')
|
||||
clear({ env={ NVIM_LISTEN_ADDRESS='Xtest-env-pipe' },
|
||||
args={ '--listen', addr } })
|
||||
eq(addr, meths.get_vvar('servername'))
|
||||
end)
|
||||
end)
|
||||
|
|
|
@ -16,6 +16,7 @@ local neq = global_helpers.neq
|
|||
local eq = global_helpers.eq
|
||||
local ok = global_helpers.ok
|
||||
local map = global_helpers.map
|
||||
local matches = global_helpers.matches
|
||||
local filter = global_helpers.filter
|
||||
local dedent = global_helpers.dedent
|
||||
local table_flatten = global_helpers.table_flatten
|
||||
|
@ -747,6 +748,7 @@ local module = {
|
|||
insert = insert,
|
||||
iswin = iswin,
|
||||
map = map,
|
||||
matches = matches,
|
||||
merge_args = merge_args,
|
||||
meth_pcall = meth_pcall,
|
||||
meths = meths,
|
||||
|
|
|
@ -16,6 +16,12 @@ end
|
|||
local function ok(res)
|
||||
return assert.is_true(res)
|
||||
end
|
||||
local function matches(pat, actual)
|
||||
if nil ~= string.match(actual, pat) then
|
||||
return true
|
||||
end
|
||||
error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual))
|
||||
end
|
||||
|
||||
-- initial_path: directory to recurse into
|
||||
-- re: include pattern (string)
|
||||
|
@ -572,6 +578,7 @@ return {
|
|||
hasenv = hasenv,
|
||||
intchar2lua = intchar2lua,
|
||||
map = map,
|
||||
matches = matches,
|
||||
mergedicts_copy = mergedicts_copy,
|
||||
neq = neq,
|
||||
ok = ok,
|
||||
|
|
Loading…
Reference in New Issue