aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/eval.txt3
-rw-r--r--src/nvim/eval.c46
-rw-r--r--src/nvim/testdir/Makefile1
-rw-r--r--src/nvim/testdir/test_system.vim48
-rw-r--r--src/nvim/version.c6
-rw-r--r--test/functional/eval/system_spec.lua10
6 files changed, 101 insertions, 13 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index ae62498d35..7820b85bf4 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -7645,6 +7645,9 @@ system({cmd} [, {input}]) *system()* *E677*
|writefile()| does with {binary} set to "b" (i.e. with
a newline between each list item, and newlines inside list
items converted to NULs).
+ When {input} is given and is a valid buffer id, the content of
+ the buffer is written to the file line by line, each line
+ terminated by a NL (and NUL where the text has NL).
*E5677*
Note: system() cannot write to or read from backgrounded ("&")
shell commands, e.g.: >
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 0d84957ac5..9de6a7c464 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -17482,24 +17482,24 @@ write_list_error:
/// Saves a typval_T as a string.
///
-/// For lists, replaces NLs with NUL and separates items with NLs.
+/// For lists or buffers, replaces NLs with NUL and separates items with NLs.
///
-/// @param[in] tv A value to store as a string.
-/// @param[out] len The length of the resulting string or -1 on error.
+/// @param[in] tv Value to store as a string.
+/// @param[out] len Length of the resulting string or -1 on error.
/// @param[in] endnl If true, the output will end in a newline (if a list).
/// @returns an allocated string if `tv` represents a VimL string, list, or
/// number; NULL otherwise.
static char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
+ *len = 0;
if (tv->v_type == VAR_UNKNOWN) {
- *len = 0;
return NULL;
}
- // For types other than list, let tv_get_string_buf_chk() get the value or
+ // For other types, let tv_get_string_buf_chk() get the value or
// print an error.
- if (tv->v_type != VAR_LIST) {
+ if (tv->v_type != VAR_LIST && tv->v_type != VAR_NUMBER) {
const char *ret = tv_get_string_chk(tv);
if (ret && (*len = strlen(ret))) {
return xmemdupz(ret, (size_t)(*len));
@@ -17509,8 +17509,40 @@ static char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
}
}
+ if (tv->v_type == VAR_NUMBER) { // Treat number as a buffer-id.
+ buf_T *buf = buflist_findnr(tv->vval.v_number);
+ if (buf) {
+ for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (char_u *p = ml_get_buf(buf, lnum, false); *p != NUL; p++) {
+ *len += 1;
+ }
+ *len += 1;
+ }
+ } else {
+ EMSGN(_(e_nobufnr), tv->vval.v_number);
+ *len = -1;
+ return NULL;
+ }
+
+ if (*len == 0) {
+ return NULL;
+ }
+
+ char *ret = xmalloc(*len + 1);
+ char *end = ret;
+ for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (char_u *p = ml_get_buf(buf, lnum, false); *p != NUL; p++) {
+ *end++ = (*p == '\n') ? NUL : *p;
+ }
+ *end++ = '\n';
+ }
+ *end = NUL;
+ *len = end - ret;
+ return ret;
+ }
+
+ assert(tv->v_type == VAR_LIST);
// Pre-calculate the resulting length.
- *len = 0;
list_T *list = tv->vval.v_list;
TV_LIST_ITER_CONST(list, li, {
*len += strlen(tv_get_string(TV_LIST_ITEM_TV(li))) + 1;
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 0c25945274..c1e6eedf94 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -88,6 +88,7 @@ NEW_TESTS ?= \
test_startup_utf8.res \
test_substitute.res \
test_syntax.res \
+ test_system.res \
test_tabpage.res \
test_textobjects.res \
test_timers.res \
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
new file mode 100644
index 0000000000..0446bd9105
--- /dev/null
+++ b/src/nvim/testdir/test_system.vim
@@ -0,0 +1,48 @@
+" Tests for system() and systemlist()
+
+function! Test_System()
+ if !executable('echo') || !executable('cat') || !executable('wc')
+ return
+ endif
+ let out = system('echo 123')
+ " On Windows we may get a trailing space.
+ if out != "123 \n"
+ call assert_equal("123\n", out)
+ endif
+
+ let out = systemlist('echo 123')
+ " On Windows we may get a trailing space and CR.
+ if out != ["123 \r"]
+ call assert_equal(['123'], out)
+ endif
+
+ call assert_equal('123', system('cat', '123'))
+ call assert_equal(['123'], systemlist('cat', '123'))
+ call assert_equal(["as\<NL>df"], systemlist('cat', ["as\<NL>df"]))
+
+ new Xdummy
+ call setline(1, ['asdf', "pw\<NL>er", 'xxxx'])
+ let out = system('wc -l', bufnr('%'))
+ " On OS/X we get leading spaces
+ let out = substitute(out, '^ *', '', '')
+ call assert_equal("3\n", out)
+
+ let out = systemlist('wc -l', bufnr('%'))
+ " On Windows we may get a trailing CR.
+ if out != ["3\r"]
+ " On OS/X we get leading spaces
+ if type(out) == v:t_list
+ let out[0] = substitute(out[0], '^ *', '', '')
+ endif
+ call assert_equal(['3'], out)
+ endif
+
+ let out = systemlist('cat', bufnr('%'))
+ " On Windows we may get a trailing CR.
+ if out != ["asdf\r", "pw\<NL>er\r", "xxxx\r"]
+ call assert_equal(['asdf', "pw\<NL>er", 'xxxx'], out)
+ endif
+ bwipe!
+
+ call assert_fails('call system("wc -l", 99999)', 'E86:')
+endfunction
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 996c06c902..2181f13c41 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -1281,10 +1281,10 @@ static const int included_patches[] = {
157,
156,
155,
- // 154,
- // 153,
+ 154,
+ 153,
152,
- // 151,
+ 151,
150,
149,
148,
diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua
index e2b12b6bc9..4d1630042b 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -5,6 +5,7 @@ local eq, call, clear, eval, feed_command, feed, nvim =
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
helpers.feed, helpers.nvim
local command = helpers.command
+local exc_exec = helpers.exc_exec
local iswin = helpers.iswin
local Screen = require('test.functional.ui.screen')
@@ -274,9 +275,12 @@ describe('system()', function()
end)
end)
- describe('input passed as Number', function()
- it('stringifies the input', function()
- eq('1', eval('system("cat", 1)'))
+ describe('Number input', function()
+ it('is treated as a buffer id', function()
+ command("put ='text in buffer 1'")
+ eq('\ntext in buffer 1\n', eval('system("cat", 1)'))
+ eq('Vim(echo):E86: Buffer 42 does not exist',
+ exc_exec('echo system("cat", 42)'))
end)
end)