changeset 20968:1c36b96522ae v8.2.1035

patch 8.2.1035: setreg() does not always clear the register Commit: https://github.com/vim/vim/commit/7633fe595e6a27d6bb376548ff89f0dcce481600 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Jun 22 19:10:56 2020 +0200 patch 8.2.1035: setreg() does not always clear the register Problem: setreg() does not always clear the register. Solution: Clear the register if the dict argument is empty. (Andy Massimino, closes #3370)
author Bram Moolenaar <Bram@vim.org>
date Mon, 22 Jun 2020 19:15:06 +0200
parents e4473542807d
children 23e89ca0b70f
files src/evalfunc.c src/testdir/test_registers.vim src/version.c
diffstat 3 files changed, 71 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6002,11 +6002,11 @@ static int	srand_seed_for_testing_is_use
 f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
 {
     if (argvars[0].v_type == VAR_UNKNOWN)
-        srand_seed_for_testing_is_used = FALSE;
+	srand_seed_for_testing_is_used = FALSE;
     else
     {
-        srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
-        srand_seed_for_testing_is_used = TRUE;
+	srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
+	srand_seed_for_testing_is_used = TRUE;
     }
 }
 
@@ -6019,7 +6019,7 @@ init_srand(UINT32_T *x)
 
     if (srand_seed_for_testing_is_used)
     {
-        *x = srand_seed_for_testing;
+	*x = srand_seed_for_testing;
 	return;
     }
 #ifndef MSWIN
@@ -7269,6 +7269,37 @@ f_setpos(typval_T *argvars, typval_T *re
 }
 
 /*
+ * Translate a register type string to the yank type and block length
+ */
+    static int
+get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
+{
+    char_u *stropt = *pp;
+    switch (*stropt)
+    {
+	case 'v': case 'c':	// character-wise selection
+	    *yank_type = MCHAR;
+	    break;
+	case 'V': case 'l':	// line-wise selection
+	    *yank_type = MLINE;
+	    break;
+	case 'b': case Ctrl_V:	// block-wise selection
+	    *yank_type = MBLOCK;
+	    if (VIM_ISDIGIT(stropt[1]))
+	    {
+		++stropt;
+		*block_len = getdigits(&stropt) - 1;
+		--stropt;
+	    }
+	    break;
+	default:
+	    return FAIL;
+    }
+    *pp = stropt;
+    return OK;
+}
+
+/*
  * "setreg()" function
  */
     static void
@@ -7302,30 +7333,31 @@ f_setreg(typval_T *argvars, typval_T *re
     if (argvars[1].v_type == VAR_DICT)
     {
 	dict_T	    *d = argvars[1].vval.v_dict;
-	dictitem_T  *di = dict_find(d, (char_u *)"regcontents", -1);
+	dictitem_T  *di;
+
+	if (d == NULL || d->dv_hashtab.ht_used == 0)
+	{
+	    // Empty dict, clear the register (like setreg(0, []))
+	    char_u *lstval[2] = {NULL, NULL};
+	    write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
+	    return;
+	}
+
+	di = dict_find(d, (char_u *)"regcontents", -1);
 	if (di != NULL)
 	    regcontents = &di->di_tv;
 
 	stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
 	if (stropt != NULL)
-	    switch (*stropt)
+	{
+	    int ret = get_yank_type(&stropt, &yank_type, &block_len);
+
+	    if (ret == FAIL || *++stropt != NUL)
 	    {
-		case 'v':		// character-wise selection
-		    yank_type = MCHAR;
-		    break;
-		case 'V':		// line-wise selection
-		    yank_type = MLINE;
-		    break;
-		case Ctrl_V:		// block-wise selection
-		    yank_type = MBLOCK;
-		    if (VIM_ISDIGIT(stropt[1]))
-		    {
-			++stropt;
-			block_len = getdigits(&stropt) - 1;
-			--stropt;
-		    }
-		    break;
+		semsg(_(e_invargval), "value");
+		return;
 	    }
+	}
 
 	if (regname == '"')
 	{
@@ -7344,6 +7376,12 @@ f_setreg(typval_T *argvars, typval_T *re
 
     if (argvars[2].v_type != VAR_UNKNOWN)
     {
+	if (yank_type != MAUTO)
+	{
+	    semsg(_(e_toomanyarg), "setreg");
+	    return;
+	}
+
 	stropt = tv_get_string_chk(&argvars[2]);
 	if (stropt == NULL)
 	    return;		// type error
@@ -7353,21 +7391,8 @@ f_setreg(typval_T *argvars, typval_T *re
 		case 'a': case 'A':	// append
 		    append = TRUE;
 		    break;
-		case 'v': case 'c':	// character-wise selection
-		    yank_type = MCHAR;
-		    break;
-		case 'V': case 'l':	// line-wise selection
-		    yank_type = MLINE;
-		    break;
-		case 'b': case Ctrl_V:	// block-wise selection
-		    yank_type = MBLOCK;
-		    if (VIM_ISDIGIT(stropt[1]))
-		    {
-			++stropt;
-			block_len = getdigits(&stropt) - 1;
-			--stropt;
-		    }
-		    break;
+		default:
+		    get_yank_type(&stropt, &yank_type, &block_len);
 	    }
     }
 
--- a/src/testdir/test_registers.vim
+++ b/src/testdir/test_registers.vim
@@ -485,6 +485,14 @@ func Test_set_register_dict()
   call assert_equal(['six'], getreginfo('0').regcontents)
   call assert_equal(['six'], getreginfo('"').regcontents)
 
+  let @x = 'one'
+  call setreg('x', {})
+  call assert_equal(1, len(split(execute('reg x'), '\n')))
+
+  call assert_fails("call setreg('0', #{regtype: 'V'}, 'v')", 'E118:')
+  call assert_fails("call setreg('0', #{regtype: 'X'})", 'E475:')
+  call assert_fails("call setreg('0', #{regtype: 'vy'})", 'E475:')
+
   bwipe!
 endfunc
 
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1035,
+/**/
     1034,
 /**/
     1033,