forked from aniani/vim
patch 7.4.1518
Problem: Channel with disconnected in/out/err is not supported. Solution: Implement it for Unix.
This commit is contained in:
33
src/eval.c
33
src/eval.c
@@ -10285,7 +10285,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
|
|||||||
* Returns NULL if the handle is invalid.
|
* Returns NULL if the handle is invalid.
|
||||||
*/
|
*/
|
||||||
static channel_T *
|
static channel_T *
|
||||||
get_channel_arg(typval_T *tv)
|
get_channel_arg(typval_T *tv, int check_open)
|
||||||
{
|
{
|
||||||
channel_T *channel = NULL;
|
channel_T *channel = NULL;
|
||||||
|
|
||||||
@@ -10304,7 +10304,7 @@ get_channel_arg(typval_T *tv)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel == NULL || !channel_is_open(channel))
|
if (check_open && (channel == NULL || !channel_is_open(channel)))
|
||||||
{
|
{
|
||||||
EMSG(_("E906: not an open channel"));
|
EMSG(_("E906: not an open channel"));
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -10318,7 +10318,7 @@ get_channel_arg(typval_T *tv)
|
|||||||
static void
|
static void
|
||||||
f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
|
f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
|
||||||
{
|
{
|
||||||
channel_T *channel = get_channel_arg(&argvars[0]);
|
channel_T *channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
|
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
{
|
{
|
||||||
@@ -10333,7 +10333,7 @@ f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
static void
|
static void
|
||||||
f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
|
f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
channel_T *channel = get_channel_arg(&argvars[0]);
|
channel_T *channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
|
|
||||||
rettv->vval.v_number = -1;
|
rettv->vval.v_number = -1;
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
@@ -10361,7 +10361,7 @@ f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
|
|||||||
static void
|
static void
|
||||||
f_ch_getjob(typval_T *argvars, typval_T *rettv)
|
f_ch_getjob(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
channel_T *channel = get_channel_arg(&argvars[0]);
|
channel_T *channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
|
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
{
|
{
|
||||||
@@ -10383,7 +10383,7 @@ f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
channel_T *channel = NULL;
|
channel_T *channel = NULL;
|
||||||
|
|
||||||
if (argvars[1].v_type != VAR_UNKNOWN)
|
if (argvars[1].v_type != VAR_UNKNOWN)
|
||||||
channel = get_channel_arg(&argvars[1]);
|
channel = get_channel_arg(&argvars[1], TRUE);
|
||||||
|
|
||||||
ch_log(channel, (char *)msg);
|
ch_log(channel, (char *)msg);
|
||||||
}
|
}
|
||||||
@@ -10500,7 +10500,7 @@ common_channel_read(typval_T *argvars, typval_T *rettv, int raw)
|
|||||||
== FAIL)
|
== FAIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
channel = get_channel_arg(&argvars[0]);
|
channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
if (channel != NULL)
|
if (channel != NULL)
|
||||||
{
|
{
|
||||||
if (opt.jo_set & JO_PART)
|
if (opt.jo_set & JO_PART)
|
||||||
@@ -10570,7 +10570,7 @@ send_common(
|
|||||||
channel_T *channel;
|
channel_T *channel;
|
||||||
int part_send;
|
int part_send;
|
||||||
|
|
||||||
channel = get_channel_arg(&argvars[0]);
|
channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
if (channel == NULL)
|
if (channel == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
part_send = channel_part_send(channel);
|
part_send = channel_part_send(channel);
|
||||||
@@ -10619,7 +10619,7 @@ ch_expr_common(typval_T *argvars, typval_T *rettv, int eval)
|
|||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = NULL;
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
channel = get_channel_arg(&argvars[0]);
|
channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
if (channel == NULL)
|
if (channel == NULL)
|
||||||
return;
|
return;
|
||||||
part_send = channel_part_send(channel);
|
part_send = channel_part_send(channel);
|
||||||
@@ -10736,7 +10736,7 @@ f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
channel_T *channel;
|
channel_T *channel;
|
||||||
jobopt_T opt;
|
jobopt_T opt;
|
||||||
|
|
||||||
channel = get_channel_arg(&argvars[0]);
|
channel = get_channel_arg(&argvars[0], TRUE);
|
||||||
if (channel == NULL)
|
if (channel == NULL)
|
||||||
return;
|
return;
|
||||||
clear_job_options(&opt);
|
clear_job_options(&opt);
|
||||||
@@ -10752,17 +10752,14 @@ f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
static void
|
static void
|
||||||
f_ch_status(typval_T *argvars, typval_T *rettv)
|
f_ch_status(typval_T *argvars, typval_T *rettv)
|
||||||
{
|
{
|
||||||
|
channel_T *channel;
|
||||||
|
|
||||||
/* return an empty string by default */
|
/* return an empty string by default */
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
if (argvars[0].v_type != VAR_CHANNEL)
|
channel = get_channel_arg(&argvars[0], FALSE);
|
||||||
{
|
rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel));
|
||||||
EMSG2(_(e_invarg2), get_tv_string(&argvars[0]));
|
|
||||||
rettv->vval.v_string = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
rettv->vval.v_string = vim_strsave(
|
|
||||||
(char_u *)channel_status(argvars[0].vval.v_channel));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -5045,11 +5045,17 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
int fd_out[2]; /* for stdout */
|
int fd_out[2]; /* for stdout */
|
||||||
int fd_err[2]; /* for stderr */
|
int fd_err[2]; /* for stderr */
|
||||||
channel_T *channel = NULL;
|
channel_T *channel = NULL;
|
||||||
|
int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
|
||||||
|
int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
|
||||||
|
int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
|
||||||
int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
|
int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
|
||||||
int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
|
int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
|
||||||
int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
|
int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
|
||||||
int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
|
int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
|
||||||
|
|
||||||
|
if (use_out_for_err && use_null_for_out)
|
||||||
|
use_null_for_err = TRUE;
|
||||||
|
|
||||||
/* default is to fail */
|
/* default is to fail */
|
||||||
job->jv_status = JOB_FAILED;
|
job->jv_status = JOB_FAILED;
|
||||||
fd_in[0] = -1;
|
fd_in[0] = -1;
|
||||||
@@ -5072,7 +5078,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pipe(fd_in) < 0)
|
else if (!use_null_for_in && pipe(fd_in) < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
if (use_file_for_out)
|
if (use_file_for_out)
|
||||||
@@ -5086,7 +5092,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pipe(fd_out) < 0)
|
else if (!use_null_for_out && pipe(fd_out) < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
if (use_file_for_err)
|
if (use_file_for_err)
|
||||||
@@ -5100,12 +5106,15 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!use_out_for_err && pipe(fd_err) < 0)
|
else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
channel = add_channel();
|
if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
|
||||||
if (channel == NULL)
|
{
|
||||||
goto failed;
|
channel = add_channel();
|
||||||
|
if (channel == NULL)
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
pid = fork(); /* maybe we should use vfork() */
|
pid = fork(); /* maybe we should use vfork() */
|
||||||
@@ -5117,6 +5126,10 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
|
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
{
|
{
|
||||||
|
# ifdef FEAT_CHANNEL
|
||||||
|
int null_fd = -1;
|
||||||
|
# endif
|
||||||
|
|
||||||
/* child */
|
/* child */
|
||||||
reset_signals(); /* handle signals normally */
|
reset_signals(); /* handle signals normally */
|
||||||
|
|
||||||
@@ -5131,15 +5144,31 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
|
|
||||||
/* TODO: re-enable this when pipes connect without a channel */
|
/* TODO: re-enable this when pipes connect without a channel */
|
||||||
# ifdef FEAT_CHANNEL
|
# ifdef FEAT_CHANNEL
|
||||||
|
if (use_null_for_in || use_null_for_out || use_null_for_err)
|
||||||
|
null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
|
||||||
|
|
||||||
/* set up stdin for the child */
|
/* set up stdin for the child */
|
||||||
if (!use_file_for_in)
|
if (use_null_for_in)
|
||||||
close(fd_in[1]);
|
{
|
||||||
close(0);
|
close(0);
|
||||||
ignored = dup(fd_in[0]);
|
ignored = dup(null_fd);
|
||||||
close(fd_in[0]);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!use_file_for_in)
|
||||||
|
close(fd_in[1]);
|
||||||
|
close(0);
|
||||||
|
ignored = dup(fd_in[0]);
|
||||||
|
close(fd_in[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/* set up stderr for the child */
|
/* set up stderr for the child */
|
||||||
if (use_out_for_err)
|
if (use_null_for_err)
|
||||||
|
{
|
||||||
|
close(2);
|
||||||
|
ignored = dup(null_fd);
|
||||||
|
}
|
||||||
|
else if (use_out_for_err)
|
||||||
{
|
{
|
||||||
close(2);
|
close(2);
|
||||||
ignored = dup(fd_out[1]);
|
ignored = dup(fd_out[1]);
|
||||||
@@ -5154,11 +5183,21 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* set up stdout for the child */
|
/* set up stdout for the child */
|
||||||
if (!use_file_for_out)
|
if (use_null_for_out)
|
||||||
close(fd_out[0]);
|
{
|
||||||
close(1);
|
close(0);
|
||||||
ignored = dup(fd_out[1]);
|
ignored = dup(null_fd);
|
||||||
close(fd_out[1]);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!use_file_for_out)
|
||||||
|
close(fd_out[0]);
|
||||||
|
close(1);
|
||||||
|
ignored = dup(fd_out[1]);
|
||||||
|
close(fd_out[1]);
|
||||||
|
}
|
||||||
|
if (null_fd >= 0)
|
||||||
|
close(null_fd);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* See above for type of argv. */
|
/* See above for type of argv. */
|
||||||
@@ -5183,17 +5222,23 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
|
|||||||
close(fd_out[1]);
|
close(fd_out[1]);
|
||||||
if (!use_out_for_err && !use_file_for_err)
|
if (!use_out_for_err && !use_file_for_err)
|
||||||
close(fd_err[1]);
|
close(fd_err[1]);
|
||||||
channel_set_pipes(channel,
|
if (channel != NULL)
|
||||||
use_file_for_in ? INVALID_FD : fd_in[1],
|
{
|
||||||
use_file_for_out ? INVALID_FD : fd_out[0],
|
channel_set_pipes(channel,
|
||||||
use_out_for_err || use_file_for_err
|
use_file_for_in || use_null_for_in
|
||||||
|
? INVALID_FD : fd_in[1],
|
||||||
|
use_file_for_out || use_null_for_out
|
||||||
|
? INVALID_FD : fd_out[0],
|
||||||
|
use_out_for_err || use_file_for_err || use_null_for_err
|
||||||
? INVALID_FD : fd_err[0]);
|
? INVALID_FD : fd_err[0]);
|
||||||
channel_set_job(channel, job, options);
|
channel_set_job(channel, job, options);
|
||||||
# ifdef FEAT_GUI
|
# ifdef FEAT_GUI
|
||||||
channel_gui_register(channel);
|
channel_gui_register(channel);
|
||||||
# endif
|
# endif
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
/* success! */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
failed: ;
|
failed: ;
|
||||||
|
@@ -1417,8 +1417,8 @@ struct channel_S {
|
|||||||
#define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT)
|
#define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
JIO_PIPE, /* default */
|
||||||
JIO_NULL,
|
JIO_NULL,
|
||||||
JIO_PIPE,
|
|
||||||
JIO_FILE,
|
JIO_FILE,
|
||||||
JIO_BUFFER,
|
JIO_BUFFER,
|
||||||
JIO_OUT
|
JIO_OUT
|
||||||
|
@@ -784,6 +784,58 @@ func Test_pipe_io_one_buffer()
|
|||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_pipe_null()
|
||||||
|
if !has('job')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
" TODO: implement this for MS-Windows
|
||||||
|
if !has('unix')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call ch_log('Test_pipe_null()')
|
||||||
|
|
||||||
|
" We cannot check that no I/O works, we only check that the job starts
|
||||||
|
" properly.
|
||||||
|
let job = job_start(s:python . " test_channel_pipe.py something",
|
||||||
|
\ {'in-io': 'null'})
|
||||||
|
call assert_equal("run", job_status(job))
|
||||||
|
try
|
||||||
|
call assert_equal('something', ch_read(job))
|
||||||
|
finally
|
||||||
|
call job_stop(job)
|
||||||
|
endtry
|
||||||
|
|
||||||
|
let job = job_start(s:python . " test_channel_pipe.py err-out",
|
||||||
|
\ {'out-io': 'null'})
|
||||||
|
call assert_equal("run", job_status(job))
|
||||||
|
try
|
||||||
|
call assert_equal('err-out', ch_read(job, {"part": "err"}))
|
||||||
|
finally
|
||||||
|
call job_stop(job)
|
||||||
|
endtry
|
||||||
|
|
||||||
|
let job = job_start(s:python . " test_channel_pipe.py something",
|
||||||
|
\ {'err-io': 'null'})
|
||||||
|
call assert_equal("run", job_status(job))
|
||||||
|
try
|
||||||
|
call assert_equal('something', ch_read(job))
|
||||||
|
finally
|
||||||
|
call job_stop(job)
|
||||||
|
endtry
|
||||||
|
|
||||||
|
let job = job_start(s:python . " test_channel_pipe.py something",
|
||||||
|
\ {'out-io': 'null', 'err-io': 'out'})
|
||||||
|
call assert_equal("run", job_status(job))
|
||||||
|
call job_stop(job)
|
||||||
|
|
||||||
|
let job = job_start(s:python . " test_channel_pipe.py something",
|
||||||
|
\ {'in-io': 'null', 'out-io': 'null', 'err-io': 'null'})
|
||||||
|
call assert_equal("run", job_status(job))
|
||||||
|
call assert_equal('channel fail', string(job_getchannel(job)))
|
||||||
|
call assert_equal('fail', ch_status(job))
|
||||||
|
call job_stop(job)
|
||||||
|
endfunc
|
||||||
|
|
||||||
""""""""""
|
""""""""""
|
||||||
|
|
||||||
let s:unletResponse = ''
|
let s:unletResponse = ''
|
||||||
|
@@ -10,7 +10,12 @@ import sys
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
print(sys.argv[1])
|
if sys.argv[1].startswith("err"):
|
||||||
|
print(sys.argv[1], file=sys.stderr)
|
||||||
|
sys.stderr.flush()
|
||||||
|
else:
|
||||||
|
print(sys.argv[1])
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
typed = sys.stdin.readline()
|
typed = sys.stdin.readline()
|
||||||
|
@@ -743,6 +743,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1518,
|
||||||
/**/
|
/**/
|
||||||
1517,
|
1517,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user