New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RDY] Use uv_getaddrinfo() for servers #6680

Merged
merged 8 commits into from May 28, 2017

Conversation

Projects
None yet
7 participants
@mhinz
Member

mhinz commented May 4, 2017

This change implicitly adds IPv6 support.

If the address contains ":", we try to use a TCP socket instead of a Unix domain
socket. Everything in front of the last occurrence of ":" is the hostname and
everything after it the port.

If the hostname lookup fails, we fall back to using a Unix domain socket.

If the port is empty ("localhost:"), a random port will be assigned.

Examples:

  NVIM_LISTEN_ADDRESS=localhost:12345  -> TCP (IPv4 or IPv6), port: 12345
  NVIM_LISTEN_ADDRESS=localhost:       -> TCP (IPv4 or IPv6), port: random (> 1024)
  NVIM_LISTEN_ADDRESS=localhost        -> Unix domain socket "localhost" in current dir

@mhinz mhinz requested review from tarruda and removed request for tarruda May 4, 2017

@jamessan

This comment has been minimized.

Member

jamessan commented May 4, 2017

Should we be using uv_getaddrinfo instead, which would also support IPv6?

@mhinz

This comment has been minimized.

Member

mhinz commented May 4, 2017

I look into it!

@oni-link

This comment has been minimized.

Contributor

oni-link commented May 4, 2017

See function socket_connect() in #6594 (https://github.com/neovim/neovim/pull/6594/files#diff-6d5b2f9d654e4e24ddb9a960da02581eR182), it already uses uv_getaddrinfo() for address lookup.

@mhinz

This comment has been minimized.

Member

mhinz commented May 5, 2017

@oni-link Thanks for the pointer!

Nevertheless, I think this will take more time than I'm willed to invest at the moment.

Does someone want to take over? Maybe @bfredl? Seems like a good addition for the already mentioned #6594.

@mhinz mhinz changed the title from [RFC] Allow NVIM_LISTEN_ADDRESS=localhost:12345 to [RFC] Use getaddrinfo() for $NVIM_LISTEN_ADDRESS May 8, 2017

@mhinz mhinz force-pushed the mhinz:listen/localhost branch from d5102a9 to d49243b May 8, 2017

for (; ai; ai = ai->ai_next) {
memcpy(&watcher->uv.tcp.addr, ai->ai_addr, ai->ai_addrlen);
result = uv_tcp_bind(&watcher->uv.tcp.handle,
(const struct sockaddr *)&watcher->uv.tcp.addr, 0);

This comment has been minimized.

@oni-link

oni-link May 8, 2017

Contributor

ai->ai_addr can be used here.

This comment has been minimized.

@mhinz

mhinz May 8, 2017

Member

Right, I guess it would be more explicit to use watcher since it's also used for all the following calls.. but using ai->ai_addr I can avoid the cast and it just looks better.

👍

@@ -90,14 +71,38 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
int result;
if (watcher->stream->type == UV_TCP) {
result = uv_tcp_bind(&watcher->uv.tcp.handle,
(const struct sockaddr *)&watcher->uv.tcp.addr, 0);
struct addrinfo *ai = watcher->uv.tcp.addrinfo;

This comment has been minimized.

@oni-link

oni-link May 8, 2017

Contributor

If ai is NULL then result is not initialized.

This comment has been minimized.

@mhinz

mhinz May 8, 2017

Member

Oops. I'll fix that.

.oO(Actually it shouldn't happen unless getaddrinfo() can return 0 and the resulting pointer to the addrinfo structures is NULL nevertheless.)

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

Since libuv is expected to return negative integers, I now initialise it with -EINVAL.

This comment has been minimized.

@ZyX-I

ZyX-I May 9, 2017

Contributor

@mhinz This should be UV_EINVAL without -, not -EINVAL. According to C99 only EDOM, EILSEQ and ERANGE must be defined, no EINVAL in this list.

This comment has been minimized.

@ZyX-I

ZyX-I May 9, 2017

Contributor

Also on Windows UV_EINVAL and -EINVAL are going to be different AFAIK. And you return UV errors in other places. Also UV_EACCESS and not -EACCESS below, UV_ENOENT and not -ENOENT.

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

👍

&(int){sizeof(struct sockaddr_storage)});
uint16_t port = (ai->ai_family == AF_INET)
? ((struct sockaddr_in *)&watcher->uv.tcp.addr)->sin_port
: ((struct sockaddr_in6 *)&watcher->uv.tcp.addr)->sin6_port;

This comment has been minimized.

@oni-link

oni-link May 8, 2017

Contributor

These numbers are encoded in network byte order, what we want is host byte order, so we need to call ntohs() on sin_port/sin6_port.
ntohs() is called later.

This comment has been minimized.

@mhinz

mhinz May 8, 2017

Member

ntohs() is used when port is used. I wanted to avoid wrapping this already huge assignment and using an extra assignment à la port = ntohs(port).

@mhinz mhinz force-pushed the mhinz:listen/localhost branch from d49243b to 9472c0c May 9, 2017

// number, a free random port number will be assigned. sin_port will
// contain 0 in this case, unless uv_tcp_getsockname() is used first.
uv_tcp_getsockname(&watcher->uv.tcp.handle,
(struct sockaddr *)&watcher->uv.tcp.addr,

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

Why not use a local struct sockaddr_storage x here? The content of x is not used in this call. Member watcher->uv.tcp.addr could be removed.

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

👍

: ((struct sockaddr_in6 *)&watcher->uv.tcp.addr)->sin6_port;
// v:servername uses the string from watcher->addr
snprintf(watcher->addr, sizeof(watcher->addr), "%s:%" PRIu16,
watcher->addr, ntohs(port));

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

Hostname is not showing for me. Could be that we reading and writing from the same buffer.

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

Hmm. Okay, I'll make a copy of watcher->addr first.

struct addrinfo *ai = watcher->uv.tcp.addrinfo;
for (; ai; ai = ai->ai_next) {
memcpy(&watcher->uv.tcp.addr, ai->ai_addr, ai->ai_addrlen);

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

This could be removed if we use a local variable, see below.

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

👍

struct addrinfo *ai = watcher->uv.tcp.addrinfo;
for (; ai; ai = ai->ai_next) {
struct sockaddr_storage sas = *(struct sockaddr_storage *)ai->ai_addr;

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

This should be moved into the if (result == 0) {...} block without initialization (uv_tcp_getsockname() will fill it). Dereferencing ai->ai_addr can go wrong if the structure is smaller than struct sockaddr_storage.

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

Dereferencing ai->ai_addr can go wrong if the structure is smaller than struct sockaddr_storage.

How would I work around that? A union with sockaddr_in and sockaddr_in6 and switching on ai_family?

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

Just put struct sockaddr_storage sas; before uv_tcp_getsockname(). We get the socket name from the socket descriptor, not from the content of sas.

// v:servername uses the string from watcher->addr
char addr[sizeof(watcher->addr)];
strcpy(addr, watcher->addr);
snprintf(watcher->addr, sizeof(addr), "%s:%" PRIu16, addr, ntohs(port));

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

Could also be done with a strlen():

size_t len = strlen(watcher->addr);
snprintf(watcher->addr +len, sizeof(watcher->addr)-len, ":%" PRIu16, ntohs(port));

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

👍

void socket_watcher_init(Loop *loop, SocketWatcher *watcher,
const char *endpoint, void *data)
void socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint,
void *data)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3)

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

We can use FUNC_ATTR_NONNULL_ARG(1,2,3) here.

void socket_watcher_init(Loop *loop, SocketWatcher *watcher,
const char *endpoint, void *data)
void socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint,
void *data)

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

Are we missing a watcher->data = data?

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

Can we just remove data from the arguments? It's always called with NULL and only in server_start(). Maybe the original author planned ahead back then.

if (uv_ip4_addr(ip, port, &watcher->uv.tcp.addr)) {
// Invalid address, treat as named pipe or unix socket
tcp = false;
char *addr = xstrdup(endpoint);

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

We could copy endpoint directly into watcher->addr and work with that string:

diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 48d4c3716..c254b8077 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -25,12 +25,12 @@ void socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoin
                          void *data)
   FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_NONNULL_ARG(3)
 {
-  char *addr = xstrdup(endpoint);
+  xstrlcpy(watcher->addr, endpoint, sizeof(watcher->addr));
+  char *addr = watcher->addr;
   char *host_end = strrchr(addr, ':');
 
   if (host_end && addr != host_end) {
     *host_end = '\0';
-    xstrlcpy(watcher->addr, addr, sizeof(watcher->addr));
 
     uv_getaddrinfo_t request;
     int retval = uv_getaddrinfo(&loop->uv, &request, NULL, addr, host_end+1,
@@ -40,6 +40,7 @@ void socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoin
                                 });
     if (retval != 0) {
       // Failed to look up address.
+      *host_end = ':';
       goto do_pipe;
     }
     watcher->uv.tcp.addrinfo = request.addrinfo;
@@ -48,7 +49,6 @@ void socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoin
     watcher->stream = (uv_stream_t *)&watcher->uv.tcp.handle;
   } else {
 do_pipe:
-    xstrlcpy(watcher->addr, endpoint, sizeof(watcher->addr));
     uv_pipe_init(&loop->uv, &watcher->uv.pipe.handle, 0);
     watcher->stream = (uv_stream_t *)&watcher->uv.pipe.handle;
   }
@@ -57,8 +57,6 @@ do_pipe:
   watcher->cb = NULL;
   watcher->close_cb = NULL;
   watcher->events = NULL;
-
-  xfree(addr);
 }
 
 int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
}
result = uv_listen(watcher->stream, backlog, connection_cb);
if (result == 0) {
struct sockaddr_storage sas = *(struct sockaddr_storage *)ai->ai_addr;

This comment has been minimized.

@oni-link

oni-link May 9, 2017

Contributor

Should be struct sockaddr_storage sas;.

This comment has been minimized.

@mhinz

mhinz May 9, 2017

Member

Oh. Ooooh. Sorry, now I get what you meant earlier. I'll fix that.

@mhinz mhinz force-pushed the mhinz:listen/localhost branch from 86dd7af to be8f20f May 9, 2017

@oni-link

This comment has been minimized.

Contributor

oni-link commented May 9, 2017

With :echo serverstart("127.0.0.1:12345678901") we have pipes in serverlist()
that kind of look like IP addresses. Is that okay?

With :echo serverstart("::1:1234567") we have tcp addresses in serverlist() that have
a different socket address (::1:54919). Probably a result of how getaddrinfo() transforms our port string into a number (1234567 % 2^16 = 54919).

@mhinz

This comment has been minimized.

Member

mhinz commented May 9, 2017

With :echo serverstart("::1:1234567") we have tcp addresses in serverlist() that have
a different socket address (::1:54919). Probably a result of how getaddrinfo() transforms our port string into a number (1234567 % 2^16 = 54919).

:echo serverstart("::1:1234567") creates a Unix socket for me, as result of falling back when getaddrinfo() failed.

@oni-link

This comment has been minimized.

Contributor

oni-link commented May 9, 2017

@mhinz, it creates a tcp socket for me. uv_getaddrinfo() does not fail. Using nc ::1 54919 -6 and sending some text, I get an answer (nc ::1 1234567 -6 also works for me).

@mhinz

This comment has been minimized.

Member

mhinz commented May 9, 2017

@oni-link Hopefully it works as expected now.

EDIT: Hmm, strtol() returns 0 if it fails.. it would be nice to support host:0 as synonym for host:, thus getting a random port assigned.

errno gets set to EINVAL, but according to my manpage that's not portable.

I replaced strtol() by getdigits_safe().

@mhinz mhinz force-pushed the mhinz:listen/localhost branch 2 times, most recently from 3e93f3c to ca39453 May 9, 2017

@oni-link

This comment has been minimized.

Contributor

oni-link commented May 9, 2017

@mhinz, port range check works.

host:0 and host: both choose a random port on my system.
With 0.0.0.0: and 0.0.0.0:0 the socket will listen on any address and picks a random port.
An empty string seems to result in a pipe with no name. Is this useful?

@mhinz

This comment has been minimized.

Member

mhinz commented May 9, 2017

You mean ' ' instead of a real empty string '', right? The latter throws an exception for me.

It would be weird, but at least on Unix it should be no problem. I'd blame the user in that case. :> And current master acts the same, so I'd say it's fine for now.

@mhinz mhinz force-pushed the mhinz:listen/localhost branch from ad60f05 to b832986 May 21, 2017

@jamessan

This comment has been minimized.

Member

jamessan commented May 22, 2017

The Linux QB failure is

11:42:41,907 WARN  - /home/quickbuild/buildagent/workspace/root/neovim/pull-requests-automated/src/nvim/event/socket.c: In function ‘socket_watcher_start’:
11:42:41,907 WARN  - /home/quickbuild/buildagent/workspace/root/neovim/pull-requests-automated/src/nvim/event/socket.c:102:11: error: conversion to ‘uint16_t’ from ‘int’ may alter its value [-Werror=conversion]

which doesn't make sense because both sin6_port and sin_port should be the same type -- in_port_t. Everywhere I've checked, that is a typedef to uint16_t. However, this is happening on Ubuntu 12.04, which is EOL, so I can't see what version of glibc it was using.

The FreeBSD QB failure is

    funcs.serverstart('127.0.0.1:')  -- assign random port
    assert(string.match(funcs.serverlist()[1], '127.0.0.1:%d+'))

on the assert:

19:17:33,940 INFO  - # test/functional/eval/server_spec.lua @ 61
19:17:33,940 INFO  - # Failure message: test/functional/eval/server_spec.lua:70: bad argument #1 to 'match' (string expected, got nil)
19:17:33,940 INFO  - # stack traceback:
19:17:33,940 INFO  - #     test/functional/eval/server_spec.lua:70: in function <test/functional/eval/server_spec.lua:61>

It'd be interesting to see what serverlist() is actually returning.

everything after it the port. If the port is empty or `0`,
a random port will be assigned.
If no address is given, it is equivalent to: >

This comment has been minimized.

@bfredl

bfredl May 22, 2017

Member

is this true also on windows (pipes have a disjoint namespace from regular files)?

This comment has been minimized.

@mhinz

mhinz May 22, 2017

Member

I have no idea. I trust the person who wrote it in the first place.

This comment has been minimized.

@bfredl

bfredl May 24, 2017

Member

I wouldn't be so trusting :P

This comment has been minimized.

@oni-link

oni-link May 28, 2017

Contributor

For Windows the special name format \\.\pipe\nvim-<PID>-<COUNTER> is used.

uv_getaddrinfo_t request;
int retval = uv_getaddrinfo(&loop->uv, &request, NULL, addr, port,
&(struct addrinfo){

This comment has been minimized.

@bfredl

bfredl May 22, 2017

Member

why not declare hints as a separate var?

This comment has been minimized.

@mhinz

mhinz May 22, 2017

Member

Well, there's no need to keep it, so I used a throwaway compound literal.

mhinz added some commits May 16, 2017

@mhinz mhinz force-pushed the mhinz:listen/localhost branch from b832986 to 156e6f2 May 22, 2017

@mhinz

This comment has been minimized.

Member

mhinz commented May 22, 2017

It'd be interesting to see what serverlist() is actually returning.

Hmm, if serverlist()[1] is nil, then serverlist() probably returned {}, right?

So serverstart('127.0.0.1:') failed whereas serverstart('127.0.0.1:0') succeeded?

@bfredl

This comment has been minimized.

Member

bfredl commented May 24, 2017

Wouldn't it be useful if serverstart("localhost:") returned the actual used address, i e "localhost:46565" ?

bfredl added a commit to bfredl/neovim that referenced this pull request May 25, 2017

PR neovim#6680
Server: use uv_getaddrinfo() for $NVIM_LISTEN_ADDRESS

This change implicitly adds IPv6 support.

If the address contains ":", we try to use a TCP socket instead of a Unix domain
socket. Everything in front of the last occurrence of ":" is the hostname and
everything after it the port.

If the hostname lookup fails, we fall back to using a Unix domain socket.

If the port is empty ("localhost:"), a random port will be assigned.

Examples:

  NVIM_LISTEN_ADDRESS=localhost:12345 -> TCP (IPv4 or IPv6), port: 12345
  NVIM_LISTEN_ADDRESS=localhost:      -> TCP (IPv4 or IPv6), port: random (> 1024)
  NVIM_LISTEN_ADDRESS=localhost:0     -> TCP (IPv4 or IPv6), port: random (> 1024)
  NVIM_LISTEN_ADDRESS=localhost       -> Unix domain socket "localhost" in current dir

Server tests: use helpers.command()

Server tests: endpoint parsing in serverstart()

Server: don't fall back to Unix sockets

Doc: explain the format for serverstart()
@mhinz

This comment has been minimized.

Member

mhinz commented May 27, 2017

@bfredl Absolutely. In a follow-up PR. :-)

@jamessan In that case I'll just ignore the Linux QB issue.

What to do about the FreeBSD QB issue? Should I just put logging into the test until we can figure it out? Is anyone using FreeBSD by any chance?

@bfredl

This comment has been minimized.

Member

bfredl commented May 27, 2017

Why? You already calculate the correct value for serverlist, why not return it already?

Server: Call uv_getaddrinfo with NULL service when no port
When using serverstart("ip.ad.d.r:") to listen on a random port, we need
to abide by getaddrinfo()'s API and pass in a NULL service, rather than
an empty string.

When given an empty string, getaddrinfo() is free to search for a
service by the given name (since the string isn't a number) which will
fail.  At least FreeBSD does perform this lookup.
@jamessan

This comment has been minimized.

Member

jamessan commented May 28, 2017

Hmm, while testing the FreeBSD fix I ran into this:

==5748==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 2 byte(s) in 1 object(s) allocated from:
    #0 0x4ecdc8 in malloc (/home/jamessan/src/github.com/neovim/build/bin/nvim+0x4ecdc8)
    #1 0xf828e4 in try_malloc /home/jamessan/src/github.com/neovim/src/nvim/memory.c:87:15
    #2 0xf82aa4 in xmalloc /home/jamessan/src/github.com/neovim/src/nvim/memory.c:121:15
    #3 0xf82f43 in xmallocz /home/jamessan/src/github.com/neovim/src/nvim/memory.c:196:15
    #4 0xf83038 in xmemdupz /home/jamessan/src/github.com/neovim/src/nvim/memory.c:214:17
    #5 0xf83e92 in xstrdup /home/jamessan/src/github.com/neovim/src/nvim/memory.c:429:10
    #6 0x175865d in vim_strsave /home/jamessan/src/github.com/neovim/src/nvim/strings.c:59:20
    #7 0xb2bdd9 in do_cmdline /home/jamessan/src/github.com/neovim/src/nvim/ex_docmd.c:553:22
    #8 0xb32b65 in do_cmdline_cmd /home/jamessan/src/github.com/neovim/src/nvim/ex_docmd.c:279:10
    #9 0xe6f0f1 in exe_pre_commands /home/jamessan/src/github.com/neovim/src/nvim/main.c:1607:7
    #10 0xe60ee8 in main /home/jamessan/src/github.com/neovim/src/nvim/main.c:335:3
    #11 0x7f74cce1a2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)

SUMMARY: AddressSanitizer: 2 byte(s) leaked in 1 allocation(s).
+++ exited with 1 +++

by running ./build/bin/nvim -u NONE -i NONE -n --cmd 'call serverstart("127.0.0.1:")' --cmd q. I tried a few other two "pre_command" command lines, but none of those leaked. I can reproduce it on master using serverstart()...

@jamessan

This comment has been minimized.

Member

jamessan commented May 28, 2017

In that case I'll just ignore the Linux QB issue.

Unfortunately, that would mean QB is red for everyone until we get off of that Ubuntu release. @jszakmeister is there any chance the QB Linux systems could be upgraded to at least Ubuntu 14.04 (Trusty)?

In the meantime, I've added a cast which should silence this.

What to do about the FreeBSD QB issue?

I've pushed a fix for that.

Wouldn't it be useful if serverstart("localhost:") returned the actual used address, i e "localhost:46565"?

Agreed. I've also pushed a commit for this.

@@ -45,6 +45,12 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher,
return UV_EINVAL;
}
if (*port == NUL) {

This comment has been minimized.

@oni-link

oni-link May 28, 2017

Contributor

Should this also be used if iport is 0 or is "0" always an acceptable port description?

This comment has been minimized.

@jamessan

jamessan May 28, 2017

Member

A port that looks like a number is used directly, otherwise a lookup is performed. We should be fine here.

// "localhost:" will now have a port), return the final value to the user.
size_t n;
char **addrs = server_address_list(&n);
address = addrs[n - 1];

This comment has been minimized.

@oni-link

oni-link May 28, 2017

Contributor

Why use address instead of rettv->vval.v_string?

This comment has been minimized.

@jamessan

jamessan May 28, 2017

Member

Fixed.

@jszakmeister

This comment has been minimized.

Member

jszakmeister commented May 28, 2017

@jszakmeister is there any chance the QB Linux systems could be upgraded to at least Ubuntu 14.04 (Trusty)?

@jamessan Yes I can. The real question, which has never been answered though, is what is our support policy? And I guess one of the additional headaches here is "what do we want to ensure we run against" vs. "what do we want to build against with no warnings"?

Let me know what you guys want here (and it's generally best to do this via email directly to me--notifications from GitHub have a tendency to get lost in the noise).

jamessan added some commits May 28, 2017

eval: serverstart: Return finalized address to user
In the process of setting up the socket watcher, the address may be
changed (e.g., adding the OS-selected port).
socket_watcher_start: Silence conversion warning for sin(6)_port
Although in_port_t is a typedef for uint16_t, GCC in Ubuntu 12.04
complains about potential loss of data due to converting int to
uint16_t.  Since we know this isn't possible, silence the warning to
avoid breaking QB until it gets upgraded to a newer Ubuntu.

@jamessan jamessan force-pushed the mhinz:listen/localhost branch from 872fab2 to 62d020a May 28, 2017

@jamessan jamessan merged commit 9cc185d into neovim:master May 28, 2017

3 of 4 checks passed

continuous-integration/appveyor/pr AppVeyor build failed
Details
QuickBuild Build pr-6680 finished with status SUCCESSFUL
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
coverage/coveralls First build on master at 75.847%
Details

@bfredl bfredl referenced this pull request May 28, 2017

Merged

[RFC] connect to socket (RPC only for the moment) #6594

5 of 6 tasks complete

@mhinz mhinz deleted the mhinz:listen/localhost branch May 31, 2017

justinmk added a commit to justinmk/neovim that referenced this pull request Nov 8, 2017

NVIM v0.2.1
FEATURES:
0e873a3 Lua(Jit) built-in neovim#4411
5b32bce Windows: `:terminal` neovim#7007
7b0ceb3 UI/API: externalize cmdline neovim#7173
b67f58b UI/API: externalize wildmenu neovim#7454
b23aa1c UI: 'winhighlight' neovim#6597
17531ed UI: command-line coloring (`:help input()-highlight`) neovim#6364
244a1f9 API: execute lua directly from the remote api neovim#6704
45626de API: `get_keymap()` neovim#6236
db99982 API: `nvim_get_hl_by_name()`, `nvim_get_hl_by_id()` neovim#7082
dc68538 menu_get() function neovim#6322
9db42d4 :cquit : take an error code argument neovim#7336
9cc185d job-control: serverstart(): support ipv6 neovim#6680
1b7a9bf job-control: sockopen() neovim#6594
6efe84a clipboard: fallback to tmux clipboard neovim#6894
6016ac2 clipboard: customize clipboard with `g:clipboard` neovim#6030
3a86dd5 ruby: override ruby host via `g:ruby_host_prog` neovim#6841
16cce1a debug: $NVIM_LOG_FILE neovim#6827
0cba3da `:checkhealth` built-in, validates $VIMRUNTIME neovim#7399

FIXES:
105d680 TUI: more terminals, improve scroll/resize neovim#6816
cb912a3 :terminal : handle F1-F12, other keys neovim#7241
619838f inccommand: improve performance neovim#6949
04b3c32 inccommand: Fix matches for zero-width neovim#7487
60b1e8a inccommand: multiline, other fixes neovim#7315
f1f7f3b inccommand: Ignore leading modifiers in the command neovim#6967
1551f71 inccommand: fix 'gdefault' lockup neovim#7262
6338199 API: bufhl: support creating new groups neovim#7414
541dde3 API: allow K_EVENT during operator-pending
8c732f7 terminal: adjust for 'number' neovim#7440
5bec946 UI: preserve wildmenu during jobs/events neovim#7110
c349083 UI: disable 'lazyredraw' during ui_refresh. neovim#6259
51808a2 send FocusGained/FocusLost event instead of pseudokey neovim#7221
133f8bc shada: preserve unnamed register on restart neovim#4700
1b70a1d shada: avoid assertion on corrupt shada file neovim#6958
9f534f3 mksession: Restore tab-local working directory neovim#6859
de1084f fix buf_write() crash neovim#7140
7f76986 syntax: register 'Normal' highlight group neovim#6973
6e7a8c3 RPC: close channel if stream was closed neovim#7081
85f3084 clipboard: disallow recursion; show hint only once neovim#7203
8d1ccb6 clipboard: performance, avoid weird edge-cases neovim#7193
01487d4 'titleold' neovim#7358
01e53a5 Windows: better path-handling, separator (slash) hygiene neovim#7349
0f2873c Windows: multibyte startup arguments neovim#7060

CHANGES:
9ff0cc7 :terminal : start in normal-mode neovim#6808
032b088 lower priority of 'cursorcolumn', 'colorcolumn' neovim#7364
2a3bcd1 RPC: Don't delay notifications when request is pending neovim#6544
023f67c :terminal : Do not change 'number', 'relativenumber' neovim#6796
1ef2d76 socket.c: Disable Nagle's algorithm on TCP sockets neovim#6915
6720fe2 help: `K` tries Vim help instead of manpage neovim#3104
7068370 help, man.vim: change "outline" map to `gO` neovim#7405

@justinmk justinmk referenced this pull request Nov 8, 2017

Merged

NVIM v0.2.1 #7505

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment