changeset 23788:d12ef361d9de v8.2.2435

patch 8.2.2435: setline() gives an error for some types Commit: https://github.com/vim/vim/commit/3445320839a38b3b0c253513b125da8298ec27d6 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jan 31 13:08:38 2021 +0100 patch 8.2.2435: setline() gives an error for some types Problem: setline() gives an error for some types. Solution: Allow any type, convert each item to a string.
author Bram Moolenaar <Bram@vim.org>
date Sun, 31 Jan 2021 13:15:04 +0100
parents 7b30bc27e54b
children 544b76283167
files runtime/doc/eval.txt src/debugger.c src/evalbuffer.c src/proto/typval.pro src/testdir/test_bufline.vim src/testdir/test_vim9_builtin.vim src/typval.c src/version.c src/vim9execute.c
diffstat 9 files changed, 96 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt*	For Vim version 8.2.  Last change: 2021 Jan 22
+*eval.txt*	For Vim version 8.2.  Last change: 2021 Jan 31
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -293,13 +293,13 @@ is not available it returns zero or the 
 
 
 List concatenation ~
-
+							*list-concatenation*
 Two lists can be concatenated with the "+" operator: >
 	:let longlist = mylist + [5, 6]
 	:let mylist += [7, 8]
 
-To prepend or append an item turn the item into a list by putting [] around
-it.  To change a list in-place see |list-modification| below.
+To prepend or append an item, turn the item into a list by putting [] around
+it.  To change a list in-place, refer to |list-modification| below.
 
 
 Sublist ~
@@ -3133,6 +3133,7 @@ append({lnum}, {text})					*append()*
 		text line below line {lnum} in the current buffer.
 		Otherwise append {text} as one text line below line {lnum} in
 		the current buffer.
+		Any type of item is accepted and converted to a String.
 		{lnum} can be zero to insert a line before the first one.
 		Returns 1 for failure ({lnum} out of range or out of memory),
 		0 for success.  Example: >
@@ -9409,6 +9410,8 @@ setline({lnum}, {text})					*setline()*
 		{lnum} is used like with |getline()|.
 		When {lnum} is just below the last line the {text} will be
 		added below the last line.
+		{text} can be any type or a List of any type, each item is
+		converted to a String.
 
 		If this succeeds, FALSE is returned.  If this fails (most likely
 		because {lnum} is invalid) TRUE is returned.
--- a/src/debugger.c
+++ b/src/debugger.c
@@ -940,9 +940,9 @@ debuggy_find(
 	    {
 		if (bp->dbg_val == NULL)
 		{
-		    debug_oldval = typval_tostring(NULL);
+		    debug_oldval = typval_tostring(NULL, TRUE);
 		    bp->dbg_val = tv;
-		    debug_newval = typval_tostring(bp->dbg_val);
+		    debug_newval = typval_tostring(bp->dbg_val, TRUE);
 		    line = TRUE;
 		}
 		else
@@ -953,11 +953,11 @@ debuggy_find(
 			typval_T *v;
 
 			line = TRUE;
-			debug_oldval = typval_tostring(bp->dbg_val);
+			debug_oldval = typval_tostring(bp->dbg_val, TRUE);
 			// Need to evaluate again, typval_compare() overwrites
 			// "tv".
 			v = eval_expr(bp->dbg_name, NULL);
-			debug_newval = typval_tostring(v);
+			debug_newval = typval_tostring(v, TRUE);
 			free_tv(bp->dbg_val);
 			bp->dbg_val = v;
 		    }
@@ -966,8 +966,8 @@ debuggy_find(
 	    }
 	    else if (bp->dbg_val != NULL)
 	    {
-		debug_oldval = typval_tostring(bp->dbg_val);
-		debug_newval = typval_tostring(NULL);
+		debug_oldval = typval_tostring(bp->dbg_val, TRUE);
+		debug_newval = typval_tostring(NULL, TRUE);
 		free_tv(bp->dbg_val);
 		bp->dbg_val = NULL;
 		line = TRUE;
--- a/src/evalbuffer.c
+++ b/src/evalbuffer.c
@@ -128,7 +128,8 @@ find_win_for_curbuf(void)
 }
 
 /*
- * Set line or list of lines in buffer "buf".
+ * Set line or list of lines in buffer "buf" to "lines".
+ * Any type is allowed and converted to a string.
  */
     static void
 set_buffer_lines(
@@ -187,7 +188,7 @@ set_buffer_lines(
 	li = l->lv_first;
     }
     else
-	line = tv_get_string_chk(lines);
+	line = typval_tostring(lines, FALSE);
 
     // default result is zero == OK
     for (;;)
@@ -197,7 +198,8 @@ set_buffer_lines(
 	    // list argument, get next string
 	    if (li == NULL)
 		break;
-	    line = tv_get_string_chk(&li->li_tv);
+	    vim_free(line);
+	    line = typval_tostring(&li->li_tv, FALSE);
 	    li = li->li_next;
 	}
 
@@ -238,6 +240,7 @@ set_buffer_lines(
 	    break;
 	++lnum;
     }
+    vim_free(line);
 
     if (added > 0)
     {
--- a/src/proto/typval.pro
+++ b/src/proto/typval.pro
@@ -21,7 +21,7 @@ char_u *tv_stringify(typval_T *varp, cha
 int tv_check_lock(typval_T *tv, char_u *name, int use_gettext);
 void copy_tv(typval_T *from, typval_T *to);
 int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, int ic);
-char_u *typval_tostring(typval_T *arg);
+char_u *typval_tostring(typval_T *arg, int quotes);
 int tv_islocked(typval_T *tv);
 int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
 int eval_option(char_u **arg, typval_T *rettv, int evaluate);
--- a/src/testdir/test_bufline.vim
+++ b/src/testdir/test_bufline.vim
@@ -5,6 +5,7 @@ source screendump.vim
 source check.vim
 
 func Test_setbufline_getbufline()
+  " similar to Test_set_get_bufline()
   new
   let b = bufnr('%')
   hide
@@ -38,6 +39,12 @@ func Test_setbufline_getbufline()
   call assert_equal(['e'], getbufline(b, 5))
   call assert_equal([], getbufline(b, 6))
   call assert_equal([], getbufline(b, 2, 1))
+
+  call setbufline(b, 2, [function('eval'), #{key: 123}, test_null_job()])
+  call assert_equal(["function('eval')",
+                  \ "{'key': 123}",
+                  \ "no process"],
+                  \ getbufline(b, 2, 4))
   exe "bwipe! " . b
 endfunc
 
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -767,6 +767,54 @@ def Test_searchcount()
   bwipe!
 enddef
 
+def Test_set_get_bufline()
+  # similar to Test_setbufline_getbufline()
+  var lines =<< trim END
+      new
+      var b = bufnr('%')
+      hide
+      assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+      assert_equal(['foo'], getbufline(b, 1))
+      assert_equal(['bar'], getbufline(b, '$'))
+      assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+      exe "bd!" b
+      assert_equal([], getbufline(b, 1, 2))
+
+      split Xtest
+      setline(1, ['a', 'b', 'c'])
+      b = bufnr('%')
+      wincmd w
+
+      assert_equal(1, setbufline(b, 5, 'x'))
+      assert_equal(1, setbufline(b, 5, ['x']))
+      assert_equal(1, setbufline(b, 5, []))
+      assert_equal(1, setbufline(b, 5, test_null_list()))
+
+      assert_equal(1, 'x'->setbufline(bufnr('$') + 1, 1))
+      assert_equal(1, ['x']->setbufline(bufnr('$') + 1, 1))
+      assert_equal(1, []->setbufline(bufnr('$') + 1, 1))
+      assert_equal(1, test_null_list()->setbufline(bufnr('$') + 1, 1))
+
+      assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$'))
+
+      assert_equal(0, setbufline(b, 4, ['d', 'e']))
+      assert_equal(['c'], b->getbufline(3))
+      assert_equal(['d'], getbufline(b, 4))
+      assert_equal(['e'], getbufline(b, 5))
+      assert_equal([], getbufline(b, 6))
+      assert_equal([], getbufline(b, 2, 1))
+
+      setbufline(b, 2, [function('eval'), {key: 123}, test_null_job()])
+      assert_equal(["function('eval')",
+                      "{'key': 123}",
+                      "no process"],
+                      getbufline(b, 2, 4))
+
+      exe 'bwipe! ' .. b
+  END
+  CheckDefAndScriptSuccess(lines)
+enddef
+
 def Test_searchdecl()
   searchdecl('blah', true, true)->assert_equal(1)
 enddef
--- a/src/typval.c
+++ b/src/typval.c
@@ -927,8 +927,13 @@ typval_compare(
     return OK;
 }
 
+/*
+ * Convert any type to a string, never give an error.
+ * When "quotes" is TRUE add quotes to a string.
+ * Returns an allocated string.
+ */
     char_u *
-typval_tostring(typval_T *arg)
+typval_tostring(typval_T *arg, int quotes)
 {
     char_u	*tofree;
     char_u	numbuf[NUMBUFLEN];
@@ -936,10 +941,18 @@ typval_tostring(typval_T *arg)
 
     if (arg == NULL)
 	return vim_strsave((char_u *)"(does not exist)");
-    ret = tv2string(arg, &tofree, numbuf, 0);
-    // Make a copy if we have a value but it's not in allocated memory.
-    if (ret != NULL && tofree == NULL)
-	ret = vim_strsave(ret);
+    if (!quotes && arg->v_type == VAR_STRING)
+    {
+	ret = vim_strsave(arg->vval.v_string == NULL ? (char_u *)""
+							 : arg->vval.v_string);
+    }
+    else
+    {
+	ret = tv2string(arg, &tofree, numbuf, 0);
+	// Make a copy if we have a value but it's not in allocated memory.
+	if (ret != NULL && tofree == NULL)
+	    ret = vim_strsave(ret);
+    }
     return ret;
 }
 
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2435,
+/**/
     2434,
 /**/
     2433,
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -879,7 +879,7 @@ do_2string(typval_T *tv, int is_2string_
 				return FAIL;
 	    }
 	}
-	str = typval_tostring(tv);
+	str = typval_tostring(tv, TRUE);
 	clear_tv(tv);
 	tv->v_type = VAR_STRING;
 	tv->vval.v_string = str;