aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt40
-rw-r--r--runtime/doc/msgpack_rpc.txt2
-rw-r--r--runtime/doc/remote.txt8
-rw-r--r--src/nvim/eval.c6
-rw-r--r--src/nvim/msgpack_rpc/server.c52
-rw-r--r--test/functional/server/server_spec.lua53
6 files changed, 110 insertions, 51 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 3865175a1f..5eb8f62d8b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1583,7 +1583,9 @@ v:scrollstart String describing the script or function that caused the
hit-enter prompt.
*v:servername* *servername-variable*
-v:servername The resulting registered |x11-clientserver| name if any.
+v:servername Default {Nvim} server address. Equivalent to
+ |$NVIM_LISTEN_ADDRESS| on startup, but may differ if the
+ latter is modified or unset. |serverstop()|
Read-only.
@@ -2366,8 +2368,8 @@ char2nr({expr}[, {utf8}]) *char2nr()*
char2nr("ABC") returns 65
< When {utf8} is omitted or zero, the current 'encoding' is used.
Example for "utf-8": >
- char2nr("á") returns 225
- char2nr("á"[0]) returns 195
+ char2nr("á") returns 225
+ char2nr("á"[0]) returns 195
< With {utf8} set to 1, always treat as utf-8 characters.
A combining character is a separate character.
|nr2char()| does the opposite.
@@ -5374,25 +5376,31 @@ server2client( {clientid}, {string}) *server2client()*
Example: >
:echo server2client(expand("<client>"), "HELLO")
<
-serverlist() *serverlist()*
+serverlist() *serverlist()*
Returns a list of available server names in a list.
When there are no servers an empty string is returned.
Example: >
:echo serverlist()
+< *--serverlist*
+ The Vim command-line option `--serverlist` can be imitated: >
+ nvim --cmd "echo serverlist()" --cmd "q"
+<
+serverstart([{address}]) *serverstart()*
+ Opens a named pipe or TCP socket at {address} for clients to
+ connect to and returns {address}. If no address is given, it
+ is equivalent to: >
+ :call serverstart(tempname())
+< |$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')"
<
-serverlisten([{address}]) *serverlisten()*
- Opens a Unix or TCP socket at {address} for clients to connect
- to and returns {address}. If no address is given, it is
- equivalent to >
- :call serverlisten(tempname())
-< If |$NVIM_LISTEN_ADDRESS| is not set, it will be set to
- {address}.
-
serverstop({address}) *serverstop()*
- Closes the Unix or TCP socket at {address}. Does nothing if
- {address} is empty, or does not refer to a server. If
- {address} equals |$NVIM_LISTEN_ADDRESS|, the listen address
- will be unset.
+ Closes the pipe or socket at {address}. Does nothing if
+ {address} is empty or invalid.
+ 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()|.
setbufvar({expr}, {varname}, {val}) *setbufvar()*
Set option or local variable {varname} in buffer {expr} to
diff --git a/runtime/doc/msgpack_rpc.txt b/runtime/doc/msgpack_rpc.txt
index b6142e2234..8304d79c17 100644
--- a/runtime/doc/msgpack_rpc.txt
+++ b/runtime/doc/msgpack_rpc.txt
@@ -81,6 +81,8 @@ There are four ways to open msgpack-rpc streams to nvim:
>
:echo $NVIM_LISTEN_ADDRESS
<
+ See also |v:servername|.
+
4. Through a TCP/IP socket. To make nvim listen on a TCP/IP socket, set the
|$NVIM_LISTEN_ADDRESS| environment variable in a shell before starting:
>
diff --git a/runtime/doc/remote.txt b/runtime/doc/remote.txt
index e84b7fc5e9..81ab72a100 100644
--- a/runtime/doc/remote.txt
+++ b/runtime/doc/remote.txt
@@ -56,11 +56,6 @@ The following command line arguments are available:
*--remote-tab-wait-silent*
--remote-tab-wait-silent Like --remote-wait-silent but open each file
in a new tabpage.
- *--servername*
- --servername {name} Become the server {name}. When used together
- with one of the --remote commands: connect to
- server {name} instead of the default (see
- below).
*--remote-send*
--remote-send {keys} Send {keys} to server and exit. The {keys}
are not mapped. Special key names are
@@ -69,9 +64,6 @@ The following command line arguments are available:
*--remote-expr*
--remote-expr {expr} Evaluate {expr} in server and print the result
on stdout.
- *--serverlist*
- --serverlist Output a list of server names.
-
Examples ~
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 906659a1f3..16b368c555 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -365,7 +365,7 @@ static struct vimvar {
} vimvars[VV_LEN] =
{
/*
- * The order here must match the VV_ defines in vim.h!
+ * The order here must match the VV_ defines in eval.h!
* Initializing a union does not work, leave tv.vval empty to get zero's.
*/
{VV_NAME("count", VAR_NUMBER), VV_COMPAT+VV_RO},
@@ -13356,7 +13356,7 @@ static void f_serverlist(typval_T *argvars, typval_T *rettv)
static void f_serverstart(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL; // Will hold the address of the new server.
+ rettv->vval.v_string = NULL; // Address of the new server
if (check_restricted() || check_secure()) {
return;
@@ -16294,7 +16294,7 @@ long get_vim_var_nr(int idx)
/*
* Get string v: variable value. Uses a static buffer, can only be used once.
*/
-char_u *get_vim_var_str(int idx)
+char_u *get_vim_var_str(int idx) FUNC_ATTR_NONNULL_RET
{
return get_tv_string(&vimvars[idx].vv_tv);
}
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 7f7291c3b9..ab1b04d73f 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -9,6 +9,7 @@
#include "nvim/msgpack_rpc/server.h"
#include "nvim/os/os.h"
#include "nvim/ascii.h"
+#include "nvim/eval.h"
#include "nvim/garray.h"
#include "nvim/vim.h"
#include "nvim/memory.h"
@@ -18,7 +19,7 @@
#define MAX_CONNECTIONS 32
#define ADDRESS_MAX_SIZE 256
-#define NEOVIM_DEFAULT_TCP_PORT 7450
+#define NVIM_DEFAULT_TCP_PORT 7450
#define LISTEN_ADDRESS_ENV_VAR "NVIM_LISTEN_ADDRESS"
typedef enum {
@@ -27,13 +28,13 @@ typedef enum {
} ServerType;
typedef struct {
- // The address of a pipe, or string value of a tcp address.
+ // Pipe/socket path, or TCP address string
char addr[ADDRESS_MAX_SIZE];
// Type of the union below
ServerType type;
- // This is either a tcp server or unix socket(named pipe on windows)
+ // TCP server or unix socket (named pipe on Windows)
union {
struct {
uv_tcp_t handle;
@@ -84,23 +85,32 @@ static void server_close_cb(Server **server)
uv_close(server_handle(*server), free_server);
}
+/// Set v:servername to the first server in the server list, or unset it if no
+/// servers are known.
+static void set_vservername(garray_T *srvs)
+{
+ char *default_server = (srvs->ga_len > 0)
+ ? ((Server **)srvs->ga_data)[0]->addr
+ : NULL;
+ set_vim_var_string(VV_SEND_SERVER, (char_u *)default_server, -1);
+}
+
/// Teardown the server module
void server_teardown(void)
{
GA_DEEP_CLEAR(&servers, Server *, server_close_cb);
}
-/// Starts listening on arbitrary tcp/unix addresses specified by
-/// `endpoint` for API calls. The type of socket used(tcp or unix/pipe) will
-/// be determined by parsing `endpoint`: If it's a valid tcp address in the
-/// 'ip[:port]' format, then it will be tcp socket. The port is optional
-/// and if omitted will default to NEOVIM_DEFAULT_TCP_PORT. Otherwise it will
-/// be a unix socket or named pipe.
+/// Starts listening for API calls on the TCP address or pipe path `endpoint`.
+/// The socket type is determined by parsing `endpoint`: If it's a valid IPv4
+/// address in 'ip[:port]' format, then it will be TCP socket. The port is
+/// optional and if omitted defaults to NVIM_DEFAULT_TCP_PORT. Otherwise it
+/// will be a unix socket or named pipe.
///
/// @param endpoint Address of the server. Either a 'ip[:port]' string or an
-/// arbitrary identifier(trimmed to 256 bytes) for the unix socket or
+/// arbitrary identifier (trimmed to 256 bytes) for the unix socket or
/// named pipe.
-/// @returns zero if successful, one on a regular error, and negative errno
+/// @returns 0 on success, 1 on a regular error, and negative errno
/// on failure to bind or connect.
int server_start(const char *endpoint)
FUNC_ATTR_NONNULL_ALL
@@ -134,14 +144,14 @@ int server_start(const char *endpoint)
size_t addr_len = (size_t)(ip_end - addr);
if (addr_len > sizeof(ip) - 1) {
- // Maximum length of an IP address buffer is 15(eg: 255.255.255.255)
+ // Maximum length of an IPv4 address buffer is 15 (eg: 255.255.255.255)
addr_len = sizeof(ip) - 1;
}
// Extract the address part
xstrlcpy(ip, addr, addr_len + 1);
- int port = NEOVIM_DEFAULT_TCP_PORT;
+ int port = NVIM_DEFAULT_TCP_PORT;
if (*ip_end == ':') {
// Extract the port
@@ -216,6 +226,11 @@ int server_start(const char *endpoint)
ga_grow(&servers, 1);
((Server **)servers.ga_data)[servers.ga_len++] = server;
+ // Update v:servername, if not set.
+ if (STRLEN(get_vim_var_str(VV_SEND_SERVER)) == 0) {
+ set_vservername(&servers);
+ }
+
return 0;
}
@@ -230,7 +245,7 @@ void server_stop(char *endpoint)
// Trim to `ADDRESS_MAX_SIZE`
xstrlcpy(addr, endpoint, sizeof(addr));
- int i = 0; // The index of the server whose address equals addr.
+ int i = 0; // Index of the server whose address equals addr.
for (; i < servers.ga_len; i++) {
server = ((Server **)servers.ga_data)[i];
if (strcmp(addr, server->addr) == 0) {
@@ -243,9 +258,9 @@ void server_stop(char *endpoint)
return;
}
- // If we are invalidating the listen address, unset it.
+ // Unset $NVIM_LISTEN_ADDRESS if it is the stopped address.
const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
- if (listen_address && strcmp(addr, listen_address) == 0) {
+ if (listen_address && STRCMP(addr, listen_address) == 0) {
os_unsetenv(LISTEN_ADDRESS_ENV_VAR);
}
@@ -257,6 +272,11 @@ void server_stop(char *endpoint)
((Server **)servers.ga_data)[servers.ga_len - 1];
}
servers.ga_len--;
+
+ // If v:servername is the stopped address, re-initialize it.
+ if (STRCMP(addr, get_vim_var_str(VV_SEND_SERVER)) == 0) {
+ set_vservername(&servers);
+ }
}
/// Returns an allocated array of server addresses.
diff --git a/test/functional/server/server_spec.lua b/test/functional/server/server_spec.lua
index 5dd8197d52..1cb3c879b9 100644
--- a/test/functional/server/server_spec.lua
+++ b/test/functional/server/server_spec.lua
@@ -4,19 +4,56 @@ local nvim, eq, neq, ok, eval
= helpers.nvim, helpers.eq, helpers.neq, helpers.ok, helpers.eval
local clear = helpers.clear
-describe('server*() functions', function()
+describe('serverstart(), serverstop()', function()
before_each(clear)
- it('set $NVIM_LISTEN_ADDRESS on first serverstart()', function()
- -- Ensure the listen address is unset.
+ it('sets $NVIM_LISTEN_ADDRESS on first invocation', function()
+ -- Unset $NVIM_LISTEN_ADDRESS
nvim('command', 'let $NVIM_LISTEN_ADDRESS = ""')
- nvim('command', 'let s = serverstart()')
- eq(1, eval('$NVIM_LISTEN_ADDRESS == s'))
- nvim('command', 'call serverstop(s)')
- eq(0, eval('$NVIM_LISTEN_ADDRESS == s'))
+
+ local s = eval('serverstart()')
+ assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
+ eq(s, eval('$NVIM_LISTEN_ADDRESS'))
+ nvim('command', "call serverstop('"..s.."')")
+ eq('', eval('$NVIM_LISTEN_ADDRESS'))
+ end)
+
+ it([[sets v:servername _only_ on nvim startup
+ (unless all servers are stopped)]], function()
+ local initial_server = eval('v:servername')
+ assert(initial_server ~= nil and initial_server:len() > 0,
+ "v:servername was not initialized")
+
+ -- v:servername is readonly so we cannot unset it--but we can test that it
+ -- does not get set again thereafter.
+ local s = eval('serverstart()')
+ assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
+ neq(initial_server, s)
+
+ -- serverstop() does _not_ modify v:servername...
+ nvim('command', "call serverstop('"..s.."')")
+ eq(initial_server, eval('v:servername'))
+
+ -- ...unless we stop _all_ servers.
+ nvim('command', "call serverstop(serverlist()[0])")
+ eq('', eval('v:servername'))
+
+ -- v:servername will take the next available server.
+ nvim('command', "call serverstart('test_server_socket')")
+ eq('test_server_socket', eval('v:servername'))
end)
- it('let the user retrieve the list of servers', function()
+ it('serverstop() ignores invalid input', function()
+ nvim('command', "call serverstop('')")
+ nvim('command', "call serverstop('bogus-socket-name')")
+ end)
+
+end)
+
+describe('serverlist()', function()
+ before_each(clear)
+
+ it('returns the list of servers', function()
-- There should already be at least one server.
local n = eval('len(serverlist())')