aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/eval.c33
-rw-r--r--src/nvim/ops.c236
-rw-r--r--src/nvim/testdir/test_eval.in145
-rw-r--r--src/nvim/testdir/test_eval.okbin432 -> 10307 bytes
-rw-r--r--src/nvim/version.c2
5 files changed, 321 insertions, 95 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 815df19476..2e2871abc5 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -13328,7 +13328,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
int regname;
char_u *strregname;
char_u *stropt;
- char_u *strval;
int append;
char_u yank_type;
long block_len;
@@ -13345,8 +13344,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
regname = *strregname;
if (regname == 0 || regname == '@')
regname = '"';
- else if (regname == '=')
- return;
if (argvars[2].v_type != VAR_UNKNOWN) {
stropt = get_tv_string_chk(&argvars[2]);
@@ -13374,10 +13371,32 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
}
}
- strval = get_tv_string_chk(&argvars[1]);
- if (strval != NULL)
- write_reg_contents_ex(regname, strval, -1,
- append, yank_type, block_len);
+ if (argvars[1].v_type == VAR_LIST) {
+ int len = argvars[1].vval.v_list->lv_len;
+ char_u **lstval = xmalloc(sizeof(char_u *) * (len + 1));
+ char_u **curval = lstval;
+
+ for (listitem_T *li = argvars[1].vval.v_list->lv_first;
+ li != NULL;
+ li = li->li_next) {
+ char_u *strval = get_tv_string_chk(&li->li_tv);
+ if (strval == NULL) {
+ free(lstval);
+ return;
+ }
+ *curval++ = strval;
+ }
+ *curval++ = NULL;
+
+ write_reg_contents_lst(regname, lstval, -1, append, yank_type, block_len);
+ free(lstval);
+ } else {
+ char_u *strval = get_tv_string_chk(&argvars[1]);
+ if (strval == NULL) {
+ return;
+ }
+ write_reg_contents_ex(regname, strval, -1, append, yank_type, block_len);
+ }
rettv->vval.v_number = 0;
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 82036b1fec..1fa8d15303 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4762,17 +4762,77 @@ void *get_reg_contents(int regname, int flags)
return retval;
}
+static bool init_write_reg(int name, struct yankreg **old_y_previous,
+ struct yankreg **old_y_current, int must_append)
+{
+ if (!valid_yank_reg(name, true)) { // check for valid reg name
+ emsg_invreg(name);
+ return false;
+ }
+
+ // Don't want to change the current (unnamed) register.
+ *old_y_previous = y_previous;
+ *old_y_current = y_current;
+
+ get_yank_register(name, true);
+ if (!y_append && !must_append) {
+ free_yank_all();
+ }
+ return true;
+}
+
+static void finish_write_reg(int name, struct yankreg *old_y_previous,
+ struct yankreg *old_y_current)
+{
+ // Send text of clipboard register to the clipboard.
+ set_clipboard(name);
+
+ // ':let @" = "val"' should change the meaning of the "" register
+ if (name != '"') {
+ y_previous = old_y_previous;
+ }
+ y_current = old_y_current;
+}
+
/// write_reg_contents - store `str` in register `name`
///
/// @see write_reg_contents_ex
-void write_reg_contents(int name,
- const char_u *str,
- ssize_t len,
+void write_reg_contents(int name, const char_u *str, ssize_t len,
int must_append)
{
write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L);
}
+void write_reg_contents_lst(int name, char_u **strings, int maxlen,
+ int must_append, int yank_type, long block_len)
+{
+ if (name == '/' || name == '=') {
+ char_u *s = strings[0];
+ if (strings[0] == NULL) {
+ s = (char_u *)"";
+ } else if (strings[1] != NULL) {
+ EMSG(_("E883: search pattern and expression register may not "
+ "contain two or more lines"));
+ return;
+ }
+ write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
+ return;
+ }
+
+ // black hole: nothing to do
+ if (name == '_') {
+ return;
+ }
+
+ struct yankreg *old_y_previous, *old_y_current;
+ if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
+ return;
+ }
+
+ str_to_reg(y_current, yank_type, (char_u *) strings, -1, block_len, true);
+ finish_write_reg(name, old_y_previous, old_y_current);
+}
+
/// write_reg_contents_ex - store `str` in register `name`
///
/// If `str` ends in '\n' or '\r', use linewise, otherwise use
@@ -4799,8 +4859,6 @@ void write_reg_contents_ex(int name,
int yank_type,
long block_len)
{
- struct yankreg *old_y_previous, *old_y_current;
-
if (len < 0) {
len = (ssize_t) STRLEN(str);
}
@@ -4834,29 +4892,16 @@ void write_reg_contents_ex(int name,
return;
}
- if (!valid_yank_reg(name, TRUE)) { /* check for valid reg name */
- emsg_invreg(name);
+ if (name == '_') { // black hole: nothing to do
return;
}
- if (name == '_') /* black hole: nothing to do */
- return;
-
- /* Don't want to change the current (unnamed) register */
- old_y_previous = y_previous;
- old_y_current = y_current;
-
- get_yank_register(name, TRUE);
- if (!y_append && !must_append)
- free_yank_all();
- str_to_reg(y_current, yank_type, str, len, block_len);
- set_clipboard(name);
-
-
- /* ':let @" = "val"' should change the meaning of the "" register */
- if (name != '"')
- y_previous = old_y_previous;
- y_current = old_y_current;
+ struct yankreg *old_y_previous, *old_y_current;
+ if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
+ return;
+ }
+ str_to_reg(y_current, yank_type, str, len, block_len, false);
+ finish_write_reg(name, old_y_previous, old_y_current);
}
/// str_to_reg - Put a string into a register.
@@ -4868,97 +4913,114 @@ void write_reg_contents_ex(int name,
/// @param str string to put in register
/// @param len length of the string
/// @param blocklen width of visual block
-static void str_to_reg(struct yankreg *y_ptr,
- int yank_type,
- const char_u *str,
- long len,
- long blocklen)
+/// @param str_list True if str is `char_u **`.
+static void str_to_reg(struct yankreg *y_ptr, int yank_type, const char_u *str,
+ long len, long blocklen, bool str_list)
{
int type; /* MCHAR, MLINE or MBLOCK */
int lnum;
long start;
long i;
int extra;
- size_t newlines; /* number of lines added */
int extraline = 0; /* extra line at the end */
int append = FALSE; /* append to last line in register */
- char_u *s;
- char_u **pp;
long maxlen;
if (y_ptr->y_array == NULL) /* NULL means empty register */
y_ptr->y_size = 0;
- if (yank_type == MAUTO)
- type = ((len > 0 && (str[len - 1] == NL || str[len - 1] == CAR))
+ if (yank_type == MAUTO) {
+ type = ((str_list ||
+ (len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
? MLINE : MCHAR);
- else
+ } else {
type = yank_type;
-
- /*
- * Count the number of lines within the string
- */
- newlines = 0;
- for (i = 0; i < len; i++)
- if (str[i] == '\n')
- ++newlines;
- if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
- extraline = 1;
- ++newlines; /* count extra newline at the end */
}
- if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
- append = TRUE;
- --newlines; /* uncount newline when appending first line */
+
+ // Count the number of lines within the string
+ size_t newlines = 0;
+ if (str_list) {
+ for (char_u **ss = (char_u **) str; *ss != NULL; ++ss) {
+ newlines++;
+ }
+ } else {
+ for (i = 0; i < len; i++) {
+ if (str[i] == '\n') {
+ ++newlines;
+ }
+ }
+ if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
+ extraline = 1;
+ ++newlines; // count extra newline at the end
+ }
+ if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
+ append = true;
+ --newlines; // uncount newline when appending first line
+ }
}
- /*
- * Allocate an array to hold the pointers to the new register lines.
- * If the register was not empty, move the existing lines to the new array.
- */
- pp = xcalloc((y_ptr->y_size + newlines), sizeof(char_u *));
- for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
+ // Allocate an array to hold the pointers to the new register lines.
+ // If the register was not empty, move the existing lines to the new array.
+ char_u **pp = xcalloc(y_ptr->y_size + newlines, sizeof(char_u *));
+ for (lnum = 0; lnum < y_ptr->y_size; ++lnum) {
pp[lnum] = y_ptr->y_array[lnum];
+ }
free(y_ptr->y_array);
y_ptr->y_array = pp;
maxlen = 0;
- /*
- * Find the end of each line and save it into the array.
- */
- for (start = 0; start < len + extraline; start += i + 1) {
- // Let i represent the length of one line.
- const char_u *p = str + start;
- i = (char_u *)xmemscan(p, '\n', len - start) - p;
- if (i > maxlen)
- maxlen = i;
- if (append) {
- --lnum;
- extra = (int)STRLEN(y_ptr->y_array[lnum]);
- } else
- extra = 0;
- s = xmalloc(i + extra + 1);
- if (extra)
- memmove(s, y_ptr->y_array[lnum], (size_t)extra);
- if (append)
- free(y_ptr->y_array[lnum]);
- if (i)
- memmove(s + extra, str + start, (size_t)i);
- extra += i;
- s[extra] = NUL;
- y_ptr->y_array[lnum++] = s;
- while (--extra >= 0) {
- if (*s == NUL)
- *s = '\n'; /* replace NUL with newline */
- ++s;
+ // Find the end of each line and save it into the array.
+ if (str_list) {
+ for (char_u **ss = (char_u **) str; *ss != NULL; ++ss, ++lnum) {
+ int i = STRLEN(*ss);
+ pp[lnum] = vim_strnsave(*ss, i);
+ if (i > maxlen) {
+ maxlen = i;
+ }
+ }
+ } else {
+ for (start = 0; start < len + extraline; start += i + 1) {
+ // Let i represent the length of one line.
+ const char_u *p = str + start;
+ i = (char_u *)xmemscan(p, '\n', len - start) - p;
+ if (i > maxlen) {
+ maxlen = i;
+ }
+ if (append) {
+ --lnum;
+ extra = (int)STRLEN(y_ptr->y_array[lnum]);
+ } else {
+ extra = 0;
+ }
+ char_u *s = xmalloc(i + extra + 1);
+ if (extra) {
+ memmove(s, y_ptr->y_array[lnum], (size_t)extra);
+ }
+ if (append) {
+ free(y_ptr->y_array[lnum]);
+ }
+ if (i) {
+ memmove(s + extra, str + start, (size_t)i);
+ }
+ extra += i;
+ s[extra] = NUL;
+ y_ptr->y_array[lnum++] = s;
+ while (--extra >= 0) {
+ if (*s == NUL) {
+ *s = '\n'; // replace NUL with newline
+ }
+ ++s;
+ }
+ append = FALSE; // only first line is appended
}
- append = FALSE; /* only first line is appended */
}
y_ptr->y_type = type;
y_ptr->y_size = lnum;
- if (type == MBLOCK)
+ if (type == MBLOCK) {
y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
- else
+ } else {
y_ptr->y_width = 0;
+ }
}
void clear_oparg(oparg_T *oap)
diff --git a/src/nvim/testdir/test_eval.in b/src/nvim/testdir/test_eval.in
index a29fefc3b6..176e62b9cc 100644
--- a/src/nvim/testdir/test_eval.in
+++ b/src/nvim/testdir/test_eval.in
@@ -1,7 +1,152 @@
+Test for various eval features. vim: set ft=vim :
+
+Note: system clipboard support is not tested. I do not think anybody will thank
+me for messing with clipboard.
+
STARTTEST
:so small.vim
:set encoding=latin1
:set noswapfile
+:lang C
+:fun AppendRegContents(reg)
+ call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1))))
+endfun
+:command -nargs=? AR :call AppendRegContents(<q-args>)
+:fun SetReg(...)
+ call call('setreg', a:000)
+ call append('$', printf('{{{2 setreg(%s)', string(a:000)[1:-2]))
+ call AppendRegContents(a:1)
+ if a:1 isnot# '='
+ execute "silent normal! Go==\n==\e\"".a:1."P"
+ endif
+endfun
+:fun ErrExe(str)
+ call append('$', 'Executing '.a:str)
+ try
+ execute a:str
+ catch
+ $put =v:exception
+ endtry
+endfun
+:fun Test()
+$put ='{{{1 let tests'
+let @" = 'abc'
+AR "
+let @" = "abc\n"
+AR "
+let @" = "abc\<C-m>"
+AR "
+let @= = '"abc"'
+AR =
+
+$put ='{{{1 Basic setreg tests'
+call SetReg('a', 'abcA', 'c')
+call SetReg('b', 'abcB', 'v')
+call SetReg('c', 'abcC', 'l')
+call SetReg('d', 'abcD', 'V')
+call SetReg('e', 'abcE', 'b')
+call SetReg('f', 'abcF', "\<C-v>")
+call SetReg('g', 'abcG', 'b10')
+call SetReg('h', 'abcH', "\<C-v>10")
+call SetReg('I', 'abcI')
+
+$put ='{{{1 Appending single lines with setreg()'
+call SetReg('A', 'abcAc', 'c')
+call SetReg('A', 'abcAl', 'l')
+call SetReg('A', 'abcAc2','c')
+call SetReg('b', 'abcBc', 'ca')
+call SetReg('b', 'abcBb', 'ba')
+call SetReg('b', 'abcBc2','ca')
+call SetReg('b', 'abcBb2','b50a')
+
+call SetReg('C', 'abcCl', 'l')
+call SetReg('C', 'abcCc', 'c')
+call SetReg('D', 'abcDb', 'b')
+
+call SetReg('E', 'abcEb', 'b')
+call SetReg('E', 'abcEl', 'l')
+call SetReg('F', 'abcFc', 'c')
+
+$put ='{{{1 Appending NL with setreg()'
+call setreg('a', 'abcA2', 'c')
+call setreg('b', 'abcB2', 'v')
+call setreg('c', 'abcC2', 'l')
+call setreg('d', 'abcD2', 'V')
+call setreg('e', 'abcE2', 'b')
+call setreg('f', 'abcF2', "\<C-v>")
+call setreg('g', 'abcG2', 'b10')
+call setreg('h', 'abcH2', "\<C-v>10")
+call setreg('I', 'abcI2')
+
+call SetReg('A', "\n")
+call SetReg('B', "\n", 'c')
+call SetReg('C', "\n")
+call SetReg('D', "\n", 'l')
+call SetReg('E', "\n")
+call SetReg('F', "\n", 'b')
+
+$put ='{{{1 Setting lists with setreg()'
+call SetReg('a', ['abcA3'], 'c')
+call SetReg('b', ['abcB3'], 'l')
+call SetReg('c', ['abcC3'], 'b')
+call SetReg('d', ['abcD3'])
+
+$put ='{{{1 Appending lists with setreg()'
+call SetReg('A', ['abcA3c'], 'c')
+call SetReg('b', ['abcB3l'], 'la')
+call SetReg('C', ['abcC3b'], 'lb')
+call SetReg('D', ['abcD32'])
+
+call SetReg('A', ['abcA32'])
+call SetReg('B', ['abcB3c'], 'c')
+call SetReg('C', ['abcC3l'], 'l')
+call SetReg('D', ['abcD3b'], 'b')
+
+$put ='{{{1 Appending lists with NL with setreg()'
+call SetReg('A', ["\n", 'abcA3l2'], 'l')
+call SetReg('B', ["\n", 'abcB3c2'], 'c')
+call SetReg('C', ["\n", 'abcC3b2'], 'b')
+call SetReg('D', ["\n", 'abcD3b50'],'b50')
+
+$put ='{{{1 Setting lists with NLs with setreg()'
+call SetReg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"])
+call SetReg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c')
+call SetReg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l')
+call SetReg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b')
+call SetReg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10')
+
+$put ='{{{1 Search and expressions'
+call SetReg('/', ['abc/'])
+call SetReg('/', ["abc/\n"])
+call SetReg('=', ['"abc/"'])
+call SetReg('=', ["\"abc/\n\""])
+
+$put ='{{{1 Errors'
+call ErrExe('call setreg()')
+call ErrExe('call setreg(1)')
+call ErrExe('call setreg(1, 2, 3, 4)')
+call ErrExe('call setreg([], 2)')
+call ErrExe('call setreg(1, {})')
+call ErrExe('call setreg(1, 2, [])')
+call ErrExe('call setreg("/", [1, 2])')
+call ErrExe('call setreg("=", [1, 2])')
+call ErrExe('call setreg(1, ["", "", [], ""])')
+endfun
+:"
+:call Test()
+:"
+:delfunction SetReg
+:delfunction AppendRegContents
+:delfunction ErrExe
+:delfunction Test
+:delcommand AR
+:call garbagecollect(1)
+:"
+:/^start:/+1,$wq! test.out
+:" vim: et ts=4 isk-=\: fmr=???,???
+:call getchar()
+:e test.out
+:%d
:" function name not starting with a capital
:try
diff --git a/src/nvim/testdir/test_eval.ok b/src/nvim/testdir/test_eval.ok
index 63b9156442..7fe5f1bd1b 100644
--- a/src/nvim/testdir/test_eval.ok
+++ b/src/nvim/testdir/test_eval.ok
Binary files differ
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 5a0d8d9d74..722a725df2 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -422,7 +422,7 @@ static int included_patches[] = {
//246,
245,
//244,
- //243,
+ 243,
242,
241,
240,