mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-07 15:37:14 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
@@ -680,6 +680,9 @@ free_buffer(buf_T *buf)
|
||||
#ifdef FEAT_RUBY
|
||||
ruby_buffer_free(buf);
|
||||
#endif
|
||||
#ifdef FEAT_JOB_CHANNEL
|
||||
channel_buffer_free(buf);
|
||||
#endif
|
||||
#ifdef FEAT_AUTOCMD
|
||||
aubuflocal_remove(buf);
|
||||
if (autocmd_busy)
|
||||
|
||||
+110
-18
@@ -61,6 +61,11 @@ static void channel_read(channel_T *channel, int part, char *func);
|
||||
/* Whether a redraw is needed for appending a line to a buffer. */
|
||||
static int channel_need_redraw = FALSE;
|
||||
|
||||
/* Whether we are inside channel_parse_messages() or another situation where it
|
||||
* is safe to invoke callbacks. */
|
||||
static int safe_to_invoke_callback = 0;
|
||||
|
||||
static char *part_names[] = {"sock", "out", "err", "in"};
|
||||
|
||||
#ifdef WIN32
|
||||
static int
|
||||
@@ -408,8 +413,15 @@ channel_free(channel_T *channel)
|
||||
{
|
||||
if (!in_free_unref_items)
|
||||
{
|
||||
channel_free_contents(channel);
|
||||
channel_free_channel(channel);
|
||||
if (safe_to_invoke_callback == 0)
|
||||
{
|
||||
channel->ch_to_be_freed = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel_free_contents(channel);
|
||||
channel_free_channel(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,6 +461,10 @@ free_unused_channels_contents(int copyID, int mask)
|
||||
int did_free = FALSE;
|
||||
channel_T *ch;
|
||||
|
||||
/* This is invoked from the garbage collector, which only runs at a safe
|
||||
* point. */
|
||||
++safe_to_invoke_callback;
|
||||
|
||||
for (ch = first_channel; ch != NULL; ch = ch->ch_next)
|
||||
if (!channel_still_useful(ch)
|
||||
&& (ch->ch_copyID & mask) != (copyID & mask))
|
||||
@@ -458,6 +474,8 @@ free_unused_channels_contents(int copyID, int mask)
|
||||
channel_free_contents(ch);
|
||||
did_free = TRUE;
|
||||
}
|
||||
|
||||
--safe_to_invoke_callback;
|
||||
return did_free;
|
||||
}
|
||||
|
||||
@@ -1073,6 +1091,7 @@ channel_set_job(channel_T *channel, job_T *job, jobopt_T *options)
|
||||
|
||||
/*
|
||||
* Find a buffer matching "name" or create a new one.
|
||||
* Returns NULL if there is something very wrong (error already reported).
|
||||
*/
|
||||
static buf_T *
|
||||
find_buffer(char_u *name, int err)
|
||||
@@ -1086,6 +1105,8 @@ find_buffer(char_u *name, int err)
|
||||
{
|
||||
buf = buflist_new(name == NULL || *name == NUL ? NULL : name,
|
||||
NULL, (linenr_T)0, BLN_LISTED);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
buf_copy_options(buf, BCO_ENTER);
|
||||
curbuf = buf;
|
||||
#ifdef FEAT_QUICKFIX
|
||||
@@ -1192,37 +1213,54 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
|
||||
|
||||
if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER)
|
||||
{
|
||||
buf_T *buf;
|
||||
|
||||
/* writing output to a buffer. Default mode is NL. */
|
||||
if (!(opt->jo_set & JO_OUT_MODE))
|
||||
channel->ch_part[PART_OUT].ch_mode = MODE_NL;
|
||||
if (opt->jo_set & JO_OUT_BUF)
|
||||
channel->ch_part[PART_OUT].ch_buffer =
|
||||
buflist_findnr(opt->jo_io_buf[PART_OUT]);
|
||||
{
|
||||
buf = buflist_findnr(opt->jo_io_buf[PART_OUT]);
|
||||
if (buf == NULL)
|
||||
EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_OUT]);
|
||||
}
|
||||
else
|
||||
channel->ch_part[PART_OUT].ch_buffer =
|
||||
find_buffer(opt->jo_io_name[PART_OUT], FALSE);
|
||||
ch_logs(channel, "writing out to buffer '%s'",
|
||||
(char *)channel->ch_part[PART_OUT].ch_buffer->b_ffname);
|
||||
{
|
||||
buf = find_buffer(opt->jo_io_name[PART_OUT], FALSE);
|
||||
}
|
||||
if (buf != NULL)
|
||||
{
|
||||
ch_logs(channel, "writing out to buffer '%s'",
|
||||
(char *)buf->b_ffname);
|
||||
channel->ch_part[PART_OUT].ch_buffer = buf;
|
||||
}
|
||||
}
|
||||
|
||||
if ((opt->jo_set & JO_ERR_IO) && (opt->jo_io[PART_ERR] == JIO_BUFFER
|
||||
|| (opt->jo_io[PART_ERR] == JIO_OUT && (opt->jo_set & JO_OUT_IO)
|
||||
&& opt->jo_io[PART_OUT] == JIO_BUFFER)))
|
||||
{
|
||||
buf_T *buf;
|
||||
|
||||
/* writing err to a buffer. Default mode is NL. */
|
||||
if (!(opt->jo_set & JO_ERR_MODE))
|
||||
channel->ch_part[PART_ERR].ch_mode = MODE_NL;
|
||||
if (opt->jo_io[PART_ERR] == JIO_OUT)
|
||||
channel->ch_part[PART_ERR].ch_buffer =
|
||||
channel->ch_part[PART_OUT].ch_buffer;
|
||||
buf = channel->ch_part[PART_OUT].ch_buffer;
|
||||
else if (opt->jo_set & JO_ERR_BUF)
|
||||
channel->ch_part[PART_ERR].ch_buffer =
|
||||
buflist_findnr(opt->jo_io_buf[PART_ERR]);
|
||||
{
|
||||
buf = buflist_findnr(opt->jo_io_buf[PART_ERR]);
|
||||
if (buf == NULL)
|
||||
EMSGN(_(e_nobufnr), (long)opt->jo_io_buf[PART_ERR]);
|
||||
}
|
||||
else
|
||||
channel->ch_part[PART_ERR].ch_buffer =
|
||||
find_buffer(opt->jo_io_name[PART_ERR], TRUE);
|
||||
ch_logs(channel, "writing err to buffer '%s'",
|
||||
(char *)channel->ch_part[PART_ERR].ch_buffer->b_ffname);
|
||||
buf = find_buffer(opt->jo_io_name[PART_ERR], TRUE);
|
||||
if (buf != NULL)
|
||||
{
|
||||
ch_logs(channel, "writing err to buffer '%s'",
|
||||
(char *)buf->b_ffname);
|
||||
channel->ch_part[PART_ERR].ch_buffer = buf;
|
||||
}
|
||||
}
|
||||
|
||||
channel->ch_part[PART_OUT].ch_io = opt->jo_io[PART_OUT];
|
||||
@@ -1392,6 +1430,29 @@ channel_write_in(channel_T *channel)
|
||||
buf->b_ml.ml_line_count - lnum + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle buffer "buf" beeing freed, remove it from any channels.
|
||||
*/
|
||||
void
|
||||
channel_buffer_free(buf_T *buf)
|
||||
{
|
||||
channel_T *channel;
|
||||
int part;
|
||||
|
||||
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
|
||||
for (part = PART_SOCK; part <= PART_IN; ++part)
|
||||
{
|
||||
chanpart_T *ch_part = &channel->ch_part[part];
|
||||
|
||||
if (ch_part->ch_buffer == buf)
|
||||
{
|
||||
ch_logs(channel, "%s buffer has been wiped out",
|
||||
part_names[part]);
|
||||
ch_part->ch_buffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write any lines waiting to be written to a channel.
|
||||
*/
|
||||
@@ -1471,6 +1532,9 @@ invoke_callback(channel_T *channel, char_u *callback, partial_T *partial,
|
||||
typval_T rettv;
|
||||
int dummy;
|
||||
|
||||
if (safe_to_invoke_callback == 0)
|
||||
EMSG("INTERNAL: Invoking callback when it is not safe");
|
||||
|
||||
argv[0].v_type = VAR_CHANNEL;
|
||||
argv[0].vval.v_channel = channel;
|
||||
|
||||
@@ -2803,7 +2867,8 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
|
||||
channel_close_on_error(channel_T *channel, char *func)
|
||||
{
|
||||
/* Do not call emsg(), most likely the other end just exited. */
|
||||
ch_errors(channel, "%s(): Cannot read from channel", func);
|
||||
ch_errors(channel, "%s(): Cannot read from channel, will close it soon",
|
||||
func);
|
||||
|
||||
/* Queue a "DETACH" netbeans message in the command queue in order to
|
||||
* terminate the netbeans session later. Do not end the session here
|
||||
@@ -2821,7 +2886,15 @@ channel_close_on_error(channel_T *channel, char *func)
|
||||
(int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
|
||||
|
||||
/* When reading from stdout is not possible, assume the other side has
|
||||
* died. */
|
||||
* died. Don't close the channel right away, it may be the wrong moment
|
||||
* to invoke callbacks. */
|
||||
channel->ch_to_be_closed = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_close_now(channel_T *channel)
|
||||
{
|
||||
ch_log(channel, "Closing channel because of previous read error");
|
||||
channel_close(channel, TRUE);
|
||||
if (channel->ch_nb_close_cb != NULL)
|
||||
(*channel->ch_nb_close_cb)();
|
||||
@@ -3531,6 +3604,8 @@ channel_parse_messages(void)
|
||||
int r;
|
||||
int part = PART_SOCK;
|
||||
|
||||
++safe_to_invoke_callback;
|
||||
|
||||
/* Only do this message when another message was given, otherwise we get
|
||||
* lots of them. */
|
||||
if (did_log_msg)
|
||||
@@ -3540,6 +3615,21 @@ channel_parse_messages(void)
|
||||
}
|
||||
while (channel != NULL)
|
||||
{
|
||||
if (channel->ch_to_be_closed)
|
||||
{
|
||||
channel->ch_to_be_closed = FALSE;
|
||||
channel_close_now(channel);
|
||||
/* channel may have been freed, start over */
|
||||
channel = first_channel;
|
||||
continue;
|
||||
}
|
||||
if (channel->ch_to_be_freed)
|
||||
{
|
||||
channel_free(channel);
|
||||
/* channel has been freed, start over */
|
||||
channel = first_channel;
|
||||
continue;
|
||||
}
|
||||
if (channel->ch_refcount == 0 && !channel_still_useful(channel))
|
||||
{
|
||||
/* channel is no longer useful, free it */
|
||||
@@ -3580,6 +3670,8 @@ channel_parse_messages(void)
|
||||
redraw_after_callback();
|
||||
}
|
||||
|
||||
--safe_to_invoke_callback;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
|
||||
void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
|
||||
void channel_set_options(channel_T *channel, jobopt_T *opt);
|
||||
void channel_set_req_callback(channel_T *channel, int part, char_u *callback, partial_T *partial, int id);
|
||||
void channel_buffer_free(buf_T *buf);
|
||||
void channel_write_any_lines(void);
|
||||
void channel_write_new_lines(buf_T *buf);
|
||||
char_u *channel_get(channel_T *channel, int part);
|
||||
|
||||
@@ -1419,6 +1419,11 @@ struct channel_S {
|
||||
char *ch_hostname; /* only for socket, allocated */
|
||||
int ch_port; /* only for socket */
|
||||
|
||||
int ch_to_be_closed; /* When TRUE reading or writing failed and
|
||||
* the channel must be closed when it's safe
|
||||
* to invoke callbacks. */
|
||||
int ch_to_be_freed; /* When TRUE channel must be freed when it's
|
||||
* safe to invoke callbacks. */
|
||||
int ch_error; /* When TRUE an error was reported. Avoids
|
||||
* giving pages full of error messages when
|
||||
* the other side has exited, only mention the
|
||||
|
||||
@@ -768,6 +768,14 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1829,
|
||||
/**/
|
||||
1828,
|
||||
/**/
|
||||
1827,
|
||||
/**/
|
||||
1826,
|
||||
/**/
|
||||
1825,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user