eval: Implement jobclose() vimscript function

This commit is contained in:
Thiago de Arruda 2015-03-28 11:40:25 -03:00
parent 028f6d7d3f
commit b8b9e5ebad
4 changed files with 79 additions and 0 deletions

View File

@ -4012,6 +4012,10 @@ items({dict}) *items()*
entry and the value of this entry. The |List| is in arbitrary
order.
jobclose({job}[, {stream}]) {Nvim} *jobclose()*
Close {job}'s {stream}, which can be one "stdin", "stdout" or
"stderr". If {stream} is omitted, all streams are closed.
jobresize({job}, {width}, {height}) {Nvim} *jobresize()*
Resize {job}'s pseudo terminal window to {width} and {height}.
This function will fail if used on jobs started without the

View File

@ -445,6 +445,7 @@ typedef struct {
Job *job;
Terminal *term;
bool exited;
bool stdin_closed;
int refcount;
ufunc_T *on_stdout, *on_stderr, *on_exit;
dict_T *self;
@ -6535,6 +6536,7 @@ static struct fst {
{"isdirectory", 1, 1, f_isdirectory},
{"islocked", 1, 1, f_islocked},
{"items", 1, 1, f_items},
{"jobclose", 1, 2, f_jobclose},
{"jobresize", 3, 3, f_jobresize},
{"jobsend", 2, 2, f_jobsend},
{"jobstart", 1, 2, f_jobstart},
@ -10658,6 +10660,48 @@ static void f_items(typval_T *argvars, typval_T *rettv)
dict_list(argvars, rettv, 2);
}
// "jobclose(id[, stream])" function
static void f_jobclose(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || (argvars[1].v_type != VAR_STRING
&& argvars[1].v_type != VAR_UNKNOWN)) {
EMSG(_(e_invarg));
return;
}
Job *job = job_find(argvars[0].vval.v_number);
if (!is_user_job(job)) {
// Invalid job id
EMSG(_(e_invjob));
return;
}
if (argvars[1].v_type == VAR_STRING) {
char *stream = (char *)argvars[1].vval.v_string;
if (!strcmp(stream, "stdin")) {
job_close_in(job);
((TerminalJobData *)job_data(job))->stdin_closed = true;
} else if (!strcmp(stream, "stdout")) {
job_close_out(job);
} else if (!strcmp(stream, "stderr")) {
job_close_err(job);
} else {
EMSG2(_("Invalid job stream \"%s\""), stream);
}
} else {
((TerminalJobData *)job_data(job))->stdin_closed = true;
job_close_streams(job);
}
}
// "jobsend()" function
static void f_jobsend(typval_T *argvars, typval_T *rettv)
{
@ -10683,6 +10727,11 @@ static void f_jobsend(typval_T *argvars, typval_T *rettv)
return;
}
if (((TerminalJobData *)job_data(job))->stdin_closed) {
EMSG(_("Can't send data to the job: stdin is closed"));
return;
}
ssize_t input_len;
char *input = (char *) save_tv_as_string(&argvars[1], &input_len, false);
if (!input) {

View File

@ -290,6 +290,18 @@ void job_close_in(Job *job) FUNC_ATTR_NONNULL_ALL
close_job_in(job);
}
// Close the job stdout stream.
void job_close_out(Job *job) FUNC_ATTR_NONNULL_ALL
{
close_job_out(job);
}
// Close the job stderr stream.
void job_close_err(Job *job) FUNC_ATTR_NONNULL_ALL
{
close_job_out(job);
}
/// All writes that complete after calling this function will be reported
/// to `cb`.
///

View File

@ -107,6 +107,20 @@ describe('jobs', function()
eq({'notification', 'exit', {0, 0}}, next_msg())
end)
it('can close the job streams with jobclose', function()
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobclose(j, "stdin")')
eq({'notification', 'exit', {0, 0}}, next_msg())
end)
it('wont allow jobsend with a job that closed stdin', function()
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobclose(j, "stdin")')
eq(false, pcall(function()
nvim('command', 'call jobsend(j, ["some data"])')
end))
end)
it('will not allow jobsend/stop on a non-existent job', function()
eq(false, pcall(eval, "jobsend(-1, 'lol')"))
eq(false, pcall(eval, "jobstop(-1)"))