mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-05-28 00:21:57 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
+77
-44
@@ -28,6 +28,8 @@
|
||||
# define ECONNREFUSED WSAECONNREFUSED
|
||||
# undef EWOULDBLOCK
|
||||
# define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
# undef EINPROGRESS
|
||||
# define EINPROGRESS WSAEINPROGRESS
|
||||
# ifdef EINTR
|
||||
# undef EINTR
|
||||
# endif
|
||||
@@ -317,20 +319,47 @@ add_channel(void)
|
||||
* Called when the refcount of a channel is zero.
|
||||
* Return TRUE if "channel" has a callback and the associated job wasn't
|
||||
* killed.
|
||||
* If the job was killed the channel is not expected to work anymore.
|
||||
* If there is no callback then nobody can get readahead.
|
||||
*/
|
||||
static int
|
||||
channel_still_useful(channel_T *channel)
|
||||
{
|
||||
int has_sock_msg;
|
||||
#ifdef CHANNEL_PIPES
|
||||
int has_out_msg;
|
||||
int has_err_msg;
|
||||
#endif
|
||||
|
||||
/* If the job was killed the channel is not expected to work anymore. */
|
||||
if (channel->ch_job_killed && channel->ch_job == NULL)
|
||||
return FALSE;
|
||||
return channel->ch_callback != NULL
|
||||
|
||||
/* If there is a close callback it may still need to be invoked. */
|
||||
if (channel->ch_close_cb != NULL)
|
||||
return TRUE;
|
||||
|
||||
/* If there is no callback then nobody can get readahead. If the fd is
|
||||
* closed and there is no readahead then the callback won't be called. */
|
||||
has_sock_msg = channel->ch_part[PART_SOCK].ch_fd != INVALID_FD
|
||||
|| channel->ch_part[PART_SOCK].ch_head.rq_next != NULL
|
||||
|| channel->ch_part[PART_SOCK].ch_json_head.jq_next != NULL;
|
||||
#ifdef CHANNEL_PIPES
|
||||
|| channel->ch_part[PART_OUT].ch_callback != NULL
|
||||
|| channel->ch_part[PART_ERR].ch_callback != NULL
|
||||
has_out_msg = channel->ch_part[PART_OUT].ch_fd != INVALID_FD
|
||||
|| channel->ch_part[PART_OUT].ch_head.rq_next != NULL
|
||||
|| channel->ch_part[PART_OUT].ch_json_head.jq_next != NULL;
|
||||
has_err_msg = channel->ch_part[PART_ERR].ch_fd != INVALID_FD
|
||||
|| channel->ch_part[PART_ERR].ch_head.rq_next != NULL
|
||||
|| channel->ch_part[PART_ERR].ch_json_head.jq_next != NULL;
|
||||
#endif
|
||||
|| channel->ch_close_cb != NULL;
|
||||
return (channel->ch_callback != NULL && (has_sock_msg
|
||||
#ifdef CHANNEL_PIPES
|
||||
|| has_out_msg || has_err_msg
|
||||
#endif
|
||||
))
|
||||
#ifdef CHANNEL_PIPES
|
||||
|| (channel->ch_part[PART_OUT].ch_callback != NULL && has_out_msg)
|
||||
|| (channel->ch_part[PART_ERR].ch_callback != NULL && has_err_msg)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -569,8 +598,6 @@ channel_open(
|
||||
#else
|
||||
int port = port_in;
|
||||
struct timeval start_tv;
|
||||
int so_error;
|
||||
socklen_t so_error_len = sizeof(so_error);
|
||||
#endif
|
||||
channel_T *channel;
|
||||
int ret;
|
||||
@@ -652,7 +679,6 @@ channel_open(
|
||||
{
|
||||
if (errno != EWOULDBLOCK
|
||||
&& errno != ECONNREFUSED
|
||||
|
||||
#ifdef EINPROGRESS
|
||||
&& errno != EINPROGRESS
|
||||
#endif
|
||||
@@ -672,14 +698,15 @@ channel_open(
|
||||
if (waittime >= 0 && ret < 0)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set rfds;
|
||||
fd_set wfds;
|
||||
#if defined(__APPLE__) && __APPLE__ == 1
|
||||
# define PASS_RFDS
|
||||
fd_set rfds;
|
||||
#ifndef WIN32
|
||||
int so_error = 0;
|
||||
socklen_t so_error_len = sizeof(so_error);
|
||||
#endif
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(sd, &rfds);
|
||||
#endif
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(sd, &wfds);
|
||||
|
||||
@@ -690,13 +717,7 @@ channel_open(
|
||||
#endif
|
||||
ch_logn(channel,
|
||||
"Waiting for connection (waittime %d msec)...", waittime);
|
||||
ret = select((int)sd + 1,
|
||||
#ifdef PASS_RFDS
|
||||
&rfds,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
&wfds, NULL, &tv);
|
||||
ret = select((int)sd + 1, &rfds, &wfds, NULL, &tv);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
@@ -708,29 +729,42 @@ channel_open(
|
||||
channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef PASS_RFDS
|
||||
if (ret == 0 && FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
|
||||
{
|
||||
/* For OS X, this implies error. See tcp(4). */
|
||||
ch_error(channel, "channel_open: Connect failed");
|
||||
EMSG(_(e_cannot_connect));
|
||||
sock_close(sd);
|
||||
channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
/* On Win32 select() is expected to work and wait for up to the
|
||||
/* On Win32: select() is expected to work and wait for up to the
|
||||
* waittime for the socket to be open. */
|
||||
if (!FD_ISSET(sd, &wfds) || ret == 0)
|
||||
#else
|
||||
/* See socket(7) for the behavior on Linux-like systems:
|
||||
/* On Linux-like systems: See socket(7) for the behavior
|
||||
* After putting the socket in non-blocking mode, connect() will
|
||||
* return EINPROGRESS, select() will not wait (as if writing is
|
||||
* possible), need to use getsockopt() to check if the socket is
|
||||
* actually open. */
|
||||
getsockopt(sd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
|
||||
if (!FD_ISSET(sd, &wfds) || ret == 0 || so_error != 0)
|
||||
* actually connect.
|
||||
* We detect an failure to connect when both read and write fds
|
||||
* are set. Use getsockopt() to find out what kind of failure. */
|
||||
if (FD_ISSET(sd, &rfds) && FD_ISSET(sd, &wfds))
|
||||
{
|
||||
ret = getsockopt(sd,
|
||||
SOL_SOCKET, SO_ERROR, &so_error, &so_error_len);
|
||||
if (ret < 0 || (so_error != 0
|
||||
&& so_error != EWOULDBLOCK
|
||||
&& so_error != ECONNREFUSED
|
||||
# ifdef EINPROGRESS
|
||||
&& so_error != EINPROGRESS
|
||||
# endif
|
||||
))
|
||||
{
|
||||
ch_errorn(channel,
|
||||
"channel_open: Connect failed with errno %d",
|
||||
so_error);
|
||||
PERROR(_(e_cannot_connect));
|
||||
sock_close(sd);
|
||||
channel_free(channel);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FD_ISSET(sd, &wfds) || so_error != 0)
|
||||
#endif
|
||||
{
|
||||
#ifndef WIN32
|
||||
@@ -1515,7 +1549,7 @@ may_invoke_callback(channel_T *channel, int part)
|
||||
{
|
||||
if (item->cq_seq_nr == seq_nr)
|
||||
{
|
||||
ch_logs(channel, "Invoking one-time callback '%s'",
|
||||
ch_logs(channel, "Invoking one-time callback %s",
|
||||
(char *)item->cq_callback);
|
||||
/* Remove the item from the list first, if the callback
|
||||
* invokes ch_close() the list will be cleared. */
|
||||
@@ -1576,7 +1610,7 @@ may_invoke_callback(channel_T *channel, int part)
|
||||
if (callback != NULL)
|
||||
{
|
||||
/* invoke the channel callback */
|
||||
ch_log(channel, "Invoking channel callback");
|
||||
ch_logs(channel, "Invoking channel callback %s", (char *)callback);
|
||||
invoke_callback(channel, callback, argv);
|
||||
}
|
||||
}
|
||||
@@ -1776,7 +1810,6 @@ channel_free_all(void)
|
||||
|
||||
/* Sent when the channel is found closed when reading. */
|
||||
#define DETACH_MSG_RAW "DETACH\n"
|
||||
#define DETACH_MSG_JSON "\"DETACH\"\n"
|
||||
|
||||
/* Buffer size for reading incoming messages. */
|
||||
#define MAXMSGSIZE 4096
|
||||
@@ -1872,7 +1905,6 @@ channel_read(channel_T *channel, int part, char *func)
|
||||
int readlen = 0;
|
||||
sock_T fd;
|
||||
int use_socket = FALSE;
|
||||
char *msg;
|
||||
|
||||
fd = channel->ch_part[part].ch_fd;
|
||||
if (fd == INVALID_FD)
|
||||
@@ -1927,11 +1959,12 @@ channel_read(channel_T *channel, int part, char *func)
|
||||
* -> ui_breakcheck
|
||||
* -> gui event loop or select loop
|
||||
* -> channel_read()
|
||||
* Don't send "DETACH" for a JS or JSON channel.
|
||||
*/
|
||||
msg = channel->ch_part[part].ch_mode == MODE_RAW
|
||||
|| channel->ch_part[part].ch_mode == MODE_NL
|
||||
? DETACH_MSG_RAW : DETACH_MSG_JSON;
|
||||
channel_save(channel, part, (char_u *)msg, (int)STRLEN(msg));
|
||||
if (channel->ch_part[part].ch_mode == MODE_RAW
|
||||
|| channel->ch_part[part].ch_mode == MODE_NL)
|
||||
channel_save(channel, part, (char_u *)DETACH_MSG_RAW,
|
||||
(int)STRLEN(DETACH_MSG_RAW));
|
||||
|
||||
/* TODO: When reading from stdout is not possible, should we try to
|
||||
* keep stdin and stderr open? Probably not, assume the other side
|
||||
|
||||
@@ -228,6 +228,8 @@ def ee(expr, g=globals(), l=locals()):
|
||||
cb.append(expr + ':' + repr((e.__class__, TypeError(msg))))
|
||||
else:
|
||||
cb.append(expr + ':' + repr((e.__class__, e)))
|
||||
elif sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte':
|
||||
msg = cb.append(expr + ':' + repr((TypeError, TypeError('expected bytes with no null'))))
|
||||
else:
|
||||
cb.append(expr + ':' + repr((e.__class__, e)))
|
||||
else:
|
||||
@@ -264,13 +266,17 @@ EOF
|
||||
:let messages=[]
|
||||
:delfunction DictNew
|
||||
py3 <<EOF
|
||||
import sys
|
||||
d=vim.bindeval('{}')
|
||||
m=vim.bindeval('messages')
|
||||
def em(expr, g=globals(), l=locals()):
|
||||
try:
|
||||
exec(expr, g, l)
|
||||
except Exception as e:
|
||||
m.extend([e.__class__.__name__])
|
||||
if sys.version_info >= (3, 5) and e.__class__ is ValueError and str(e) == 'embedded null byte':
|
||||
m.extend([TypeError.__name__])
|
||||
else:
|
||||
m.extend([e.__class__.__name__])
|
||||
|
||||
em('d["abc1"]')
|
||||
em('d["abc1"]="\\0"')
|
||||
|
||||
@@ -535,14 +535,21 @@ endfunc
|
||||
|
||||
func Test_exit_callback()
|
||||
if has('job')
|
||||
call ch_log('Test_exit_callback()')
|
||||
call s:run_server('s:test_exit_callback')
|
||||
|
||||
" the job may take a little while to exit
|
||||
sleep 50m
|
||||
" wait up to a second for the job to exit
|
||||
for i in range(100)
|
||||
if s:job_exit_ret == 'done'
|
||||
break
|
||||
endif
|
||||
sleep 10m
|
||||
" calling job_status() triggers the callback
|
||||
call job_status(s:exit_job)
|
||||
endfor
|
||||
|
||||
" calling job_status() triggers the callback
|
||||
call job_status(s:exit_job)
|
||||
call assert_equal('done', s:job_exit_ret)
|
||||
unlet s:exit_job
|
||||
endif
|
||||
endfunc
|
||||
|
||||
@@ -571,3 +578,5 @@ func Test_close_callback()
|
||||
call s:run_server('s:test_close_callback')
|
||||
endfunc
|
||||
|
||||
" Uncomment this to see what happens, output is in src/testdir/channellog.
|
||||
" call ch_logfile('channellog', 'w')
|
||||
|
||||
@@ -82,8 +82,7 @@ func Test_json_encode()
|
||||
|
||||
if has('multi_byte')
|
||||
call assert_equal(s:jsonmb, json_encode(s:varmb))
|
||||
call assert_equal(s:varsp1, json_decode(s:jsonsp1))
|
||||
call assert_equal(s:varsp2, json_decode(s:jsonsp2))
|
||||
" no test for surrogate pair, json_encode() doesn't create them.
|
||||
endif
|
||||
|
||||
call assert_equal(s:jsonnr, json_encode(s:varnr))
|
||||
@@ -120,8 +119,8 @@ func Test_json_decode()
|
||||
|
||||
if has('multi_byte')
|
||||
call assert_equal(s:varmb, json_decode(s:jsonmb))
|
||||
call assert_equal(s:varsp1, js_decode(s:jsonsp1))
|
||||
call assert_equal(s:varsp2, js_decode(s:jsonsp2))
|
||||
call assert_equal(s:varsp1, json_decode(s:jsonsp1))
|
||||
call assert_equal(s:varsp2, json_decode(s:jsonsp2))
|
||||
endif
|
||||
|
||||
call assert_equal(s:varnr, json_decode(s:jsonnr))
|
||||
@@ -185,6 +184,7 @@ func Test_js_encode()
|
||||
|
||||
if has('multi_byte')
|
||||
call assert_equal(s:jsonmb, js_encode(s:varmb))
|
||||
" no test for surrogate pair, js_encode() doesn't create them.
|
||||
endif
|
||||
|
||||
call assert_equal(s:jsonnr, js_encode(s:varnr))
|
||||
@@ -223,6 +223,8 @@ func Test_js_decode()
|
||||
|
||||
if has('multi_byte')
|
||||
call assert_equal(s:varmb, js_decode(s:jsonmb))
|
||||
call assert_equal(s:varsp1, js_decode(s:jsonsp1))
|
||||
call assert_equal(s:varsp2, js_decode(s:jsonsp2))
|
||||
endif
|
||||
|
||||
call assert_equal(s:varnr, js_decode(s:jsonnr))
|
||||
|
||||
@@ -758,6 +758,18 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1459,
|
||||
/**/
|
||||
1458,
|
||||
/**/
|
||||
1457,
|
||||
/**/
|
||||
1456,
|
||||
/**/
|
||||
1455,
|
||||
/**/
|
||||
1454,
|
||||
/**/
|
||||
1453,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user