diff options
-rw-r--r-- | runtime/doc/eval.txt | 5 | ||||
-rw-r--r-- | src/nvim/eval.c | 17 | ||||
-rw-r--r-- | test/functional/shell/viml_system_spec.lua | 22 |
3 files changed, 38 insertions, 6 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 91a9f1292f..0778cf6122 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -6188,11 +6188,12 @@ system({expr} [, {input}]) *system()* *E677* Use |:checktime| to force a check. -systemlist({expr} [, {input}]) *systemlist()* +systemlist({expr} [, {input} [, {keepempty}]]) *systemlist()* Same as |system()|, but returns a |List| with lines (parts of output separated by NL) with NULs transformed into NLs. Output is the same as |readfile()| will output with {binary} argument - set to "b". + set to "b", except that a final newline is not preserved, + unless {keepempty} is present and it's non-zero. Returns an empty string on error, so be careful not to run into |E706|. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 8be25bc34e..be69bdbe61 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6593,7 +6593,7 @@ static struct fst { {"synconcealed", 2, 2, f_synconcealed}, {"synstack", 2, 2, f_synstack}, {"system", 1, 2, f_system}, - {"systemlist", 1, 2, f_systemlist}, + {"systemlist", 1, 3, f_systemlist}, {"tabpagebuflist", 0, 1, f_tabpagebuflist}, {"tabpagenr", 0, 1, f_tabpagenr}, {"tabpagewinnr", 1, 2, f_tabpagewinnr}, @@ -14523,7 +14523,7 @@ static void f_synstack(typval_T *argvars, typval_T *rettv) } } -static list_T* string_to_list(char_u *str, size_t len) +static list_T* string_to_list(char_u *str, size_t len, bool keepempty) { list_T *list = list_alloc(); @@ -14543,6 +14543,11 @@ static list_T* string_to_list(char_u *str, size_t len) list_append(list, li); } + // Optionally retain final newline, if present + if (keepempty && str[len-1] == NL) { + list_append_string(list, (char_u*)"", 0); + } + return list; } @@ -14585,7 +14590,11 @@ static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, } if (retlist) { - rettv->vval.v_list = string_to_list((char_u *) res, nread); + int keepempty = 0; + if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { + keepempty = get_tv_number(&argvars[2]); + } + rettv->vval.v_list = string_to_list((char_u *) res, nread, keepempty != 0); rettv->vval.v_list->lv_refcount++; rettv->v_type = VAR_LIST; @@ -19723,7 +19732,7 @@ static void apply_job_autocmds(int id, char *name, char *type, str_slot->li_tv.v_type = VAR_LIST; str_slot->li_tv.v_lock = 0; str_slot->li_tv.vval.v_list = - string_to_list((char_u *) received, received_len); + string_to_list((char_u *) received, received_len, false); str_slot->li_tv.vval.v_list->lv_refcount++; list_append(list, str_slot); diff --git a/test/functional/shell/viml_system_spec.lua b/test/functional/shell/viml_system_spec.lua index 8d212c1375..48dc518d7b 100644 --- a/test/functional/shell/viml_system_spec.lua +++ b/test/functional/shell/viml_system_spec.lua @@ -188,6 +188,28 @@ describe('systemlist()', function() end) end) + describe('handles empty lines', function() + it('in the middle', function() + eq({'line one','','line two'}, eval("systemlist('cat',['line one','','line two'])")) + end) + + it('in the beginning', function() + eq({'','line one','line two'}, eval("systemlist('cat',['','line one','line two'])")) + end) + end) + + describe('when keepempty option is', function() + it('0, ignores trailing newline', function() + eq({'aa','bb'}, eval("systemlist('cat',['aa','bb'],0)")) + eq({'aa','bb'}, eval("systemlist('cat',['aa','bb',''],0)")) + end) + + it('1, preserves trailing newline', function() + eq({'aa','bb'}, eval("systemlist('cat',['aa','bb'],1)")) + eq({'aa','bb',''}, eval("systemlist('cat',['aa','bb',''],2)")) + end) + end) + if xclip then describe("with a program that doesn't close stdout", function() it('will exit properly after passing input', function() |