aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Prager <splinterofchaos@gmail.com>2014-10-25 21:45:13 -0400
committerThiago de Arruda <tpadilha84@gmail.com>2014-11-07 13:34:56 -0300
commite90973e0359b782a6e3ad4997258d9ca42495c2f (patch)
tree29527fb1a2227b3d4d27a6665b5eb220dae07dd6
parent37cbafa5bbf01c2619f009bdf876dd4453e9a28a (diff)
downloadrneovim-e90973e0359b782a6e3ad4997258d9ca42495c2f.tar.gz
rneovim-e90973e0359b782a6e3ad4997258d9ca42495c2f.tar.bz2
rneovim-e90973e0359b782a6e3ad4997258d9ca42495c2f.zip
job: Make v:job_data[2] a list.
Factor out string_to_list() from f_system()'s implementation and use that to set job_data. This has the technical advantage of preserving NULs, and may be more convenient for users. Required for #1176.
-rw-r--r--runtime/doc/job_control.txt8
-rw-r--r--src/nvim/eval.c51
-rw-r--r--test/functional/job/job_spec.lua32
3 files changed, 59 insertions, 32 deletions
diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt
index 49ee3889bc..226244875d 100644
--- a/runtime/doc/job_control.txt
+++ b/runtime/doc/job_control.txt
@@ -47,9 +47,9 @@ event. The best way to understand is with a complete example:
function JobHandler()
if v:job_data[1] == 'stdout'
- let str = 'shell '. v:job_data[0].' stdout: '.v:job_data[2]
+ let str = 'shell '. v:job_data[0].' stdout: '.join(v:job_data[2])
elseif v:job_data[1] == 'stderr'
- let str = 'shell '.v:job_data[0].' stderr: '.v:job_data[2]
+ let str = 'shell '.v:job_data[0].' stderr: '.join(v:job_data[2])
else
let str = 'shell '.v:job_data[0].' exited'
endif
@@ -80,8 +80,8 @@ Here's what is happening:
following elements:
0: The job id
1: The kind of activity: one of "stdout", "stderr" or "exit"
- 2: When "activity" is "stdout" or "stderr", this will contain the data read
- from stdout or stderr
+ 2: When "activity" is "stdout" or "stderr", this will contain a list of
+ lines read from stdout or stderr
To send data to the job's stdin, one can use the |jobsend()| function, like
this:
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a58745f22a..ae40a10937 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -14434,6 +14434,29 @@ static void f_synstack(typval_T *argvars, typval_T *rettv)
}
}
+static list_T* string_to_list(char_u *str, size_t len)
+{
+ list_T *list = list_alloc();
+
+ // Copy each line to a list element using NL as the delimiter.
+ for (size_t i = 0; i < len; i++) {
+ char_u *start = str + i;
+ size_t line_len = (char_u *) xmemscan(start, NL, len - i) - start;
+ i += line_len;
+
+ // Don't use a str function to copy res as it may contains NULs.
+ char_u *s = xmemdupz(start, line_len);
+ memchrsub(s, NUL, NL, line_len); // Replace NUL with NL to avoid truncation
+
+ listitem_T *li = listitem_alloc();
+ li->li_tv.v_type = VAR_STRING;
+ li->li_tv.vval.v_string = s;
+ list_append(list, li);
+ }
+
+ return list;
+}
+
static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
bool retlist)
{
@@ -14468,23 +14491,9 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
}
if (retlist) {
- list_T *list = rettv_list_alloc(rettv);
-
- // Copy each line to a list element using NL as the delimiter.
- for (size_t i = 0; i < nread; i++) {
- char_u *start = (char_u *) res + i;
- size_t len = (char_u *) xmemscan(start, NL, nread - i) - start;
- i += len;
-
- // Don't use a str function to copy res as it may contains NULs.
- char_u *s = xmemdupz(start, len);
- memchrsub(s, NUL, NL, len); // Replace NUL with NL to avoid truncation.
-
- listitem_T *li = listitem_alloc();
- li->li_tv.v_type = VAR_STRING;
- li->li_tv.vval.v_string = s;
- list_append(list, li);
- }
+ rettv->vval.v_list = string_to_list((char_u *) res, nread);
+ rettv->vval.v_list->lv_refcount++;
+ rettv->v_type = VAR_LIST;
free(res);
} else {
@@ -19603,10 +19612,14 @@ static void apply_job_autocmds(int id, char *name, char *type,
if (received) {
listitem_T *str_slot = listitem_alloc();
- str_slot->li_tv.v_type = VAR_STRING;
+ str_slot->li_tv.v_type = VAR_LIST;
str_slot->li_tv.v_lock = 0;
- str_slot->li_tv.vval.v_string = (uint8_t *)received;
+ str_slot->li_tv.vval.v_list =
+ string_to_list((char_u *) received, received_len);
+ str_slot->li_tv.vval.v_list->lv_refcount++;
list_append(list, str_slot);
+
+ free(received);
}
// Update v:job_data for the autocommands
diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua
index 9046d85f10..51218288a5 100644
--- a/test/functional/job/job_spec.lua
+++ b/test/functional/job/job_spec.lua
@@ -11,8 +11,12 @@ describe('jobs', function()
before_each(clear)
-- Creates the string to make an autocmd to notify us.
- local notify_str = function(expr)
- return "au! JobActivity xxx call rpcnotify("..channel..", "..expr..")"
+ local notify_str = function(expr1, expr2)
+ local str = "au! JobActivity xxx call rpcnotify("..channel..", "..expr1
+ if expr2 ~= nil then
+ str = str..", "..expr2
+ end
+ return str..")"
end
local notify_job = function()
@@ -33,18 +37,28 @@ describe('jobs', function()
end)
it('allows interactive commands', function()
- nvim('command', notify_str('v:job_data[2]'))
+ nvim('command', notify_str('v:job_data[1]', 'v:job_data[2]'))
nvim('command', "let j = jobstart('xxx', 'cat', ['-'])")
neq(0, eval('j'))
- nvim('command', "call jobsend(j, 'abc')")
- eq({'notification', 'abc', {}}, next_message())
- nvim('command', "call jobsend(j, '123')")
- eq({'notification', '123', {}}, next_message())
+ nvim('command', 'call jobsend(j, "abc\\n")')
+ eq({'notification', 'stdout', {{'abc'}}}, next_message())
+ nvim('command', 'call jobsend(j, "123\\nxyz\\n")')
+ eq({'notification', 'stdout', {{'123', 'xyz'}}}, next_message())
nvim('command', notify_str('v:job_data[1])'))
nvim('command', "call jobstop(j)")
eq({'notification', 'exit', {}}, next_message())
end)
+ it('will hold data if it does not end in a newline', function()
+ nvim('command', notify_str('v:job_data[1]', 'v:job_data[2]'))
+ nvim('command', "let j = jobstart('xxx', 'cat', ['-'])")
+ nvim('command', 'call jobsend(j, "abc\\nxyz")')
+ eq({'notification', 'stdout', {{'abc'}}}, next_message())
+ nvim('command', "call jobstop(j)")
+ eq({'notification', 'stdout', {{'xyz'}}}, next_message())
+ 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, 'lol')"))
@@ -65,9 +79,9 @@ describe('jobs', function()
nvim('command', notify_job())
nvim('command', "let j = jobstart('xxx', 'cat', ['-'])")
local jobid = nvim('eval', 'j')
- nvim('eval', 'jobsend(j, "abc\ndef")')
+ nvim('eval', 'jobsend(j, "abcdef")')
nvim('eval', 'jobstop(j)')
- eq({'notification', 'j', {{jobid, 'stdout', 'abc\ndef'}}}, next_message())
+ eq({'notification', 'j', {{jobid, 'stdout', {'abcdef'}}}}, next_message())
eq({'notification', 'j', {{jobid, 'exit'}}}, next_message())
end)
end)