changeset 24512:53871095bb65 v8.2.2796

patch 8.2.2796: Vim9: redir to variable does not accept an index Commit: https://github.com/vim/vim/commit/753bcf8c7d7cf7b9e1572a80cc513a67020814ac Author: Bram Moolenaar <Bram@vim.org> Date: Wed Apr 21 14:24:24 2021 +0200 patch 8.2.2796: Vim9: redir to variable does not accept an index Problem: Vim9: redir to variable does not accept an index. Solution: Make the index work.
author Bram Moolenaar <Bram@vim.org>
date Wed, 21 Apr 2021 14:30:04 +0200
parents 2aaa71ea39fb
children e9bced689811
files src/testdir/test_vim9_cmd.vim src/version.c src/vim9compile.c
diffstat 3 files changed, 66 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -1212,10 +1212,35 @@ def Test_redir_to_var()
   redir END
   assert_equal("\nsomething\nmore", result)
 
+  var d: dict<string>
+  redir => d.redir
+    echo 'dict'
+  redir END
+  assert_equal({redir: "\ndict"}, d)
+
+  var l = ['a', 'b', 'c']
+  redir => l[1]
+    echo 'list'
+  redir END
+  assert_equal(['a', "\nlist", 'c'], l)
+
+  var dl = {l: ['x']}
+  redir => dl.l[0]
+    echo 'dict-list'
+  redir END
+  assert_equal({l: ["\ndict-list"]}, dl)
+
   var lines =<< trim END
     redir => notexist
   END
   CheckDefFailure(lines, 'E1089:')
+
+  lines =<< trim END
+    var ls = 'asdf'
+    redir => ls[1]
+    redir END
+  END
+  CheckDefFailure(lines, 'E1141:')
 enddef
 
 
--- 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 */
 /**/
+    2796,
+/**/
     2795,
 /**/
     2794,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -134,10 +134,14 @@ typedef enum {
 typedef struct {
     assign_dest_T   lhs_dest;	    // type of destination
 
-    char_u	    *lhs_name;	    // allocated name including
+    char_u	    *lhs_name;	    // allocated name excluding the last
 				    // "[expr]" or ".name".
     size_t	    lhs_varlen;	    // length of the variable without
 				    // "[expr]" or ".name"
+    char_u	    *lhs_whole;	    // allocated name including the last
+				    // "[expr]" or ".name" for :redir
+    size_t	    lhs_varlen_total; // length of the variable including
+				      // any "[expr]" or ".name"
     char_u	    *lhs_dest_end;  // end of the destination, including
 				    // "[expr]" or ".name".
 
@@ -5845,6 +5849,7 @@ compile_lhs(
 
     // compute the length of the destination without "[expr]" or ".name"
     lhs->lhs_varlen = var_end - var_start;
+    lhs->lhs_varlen_total = lhs->lhs_varlen;
     lhs->lhs_name = vim_strnsave(var_start, lhs->lhs_varlen);
     if (lhs->lhs_name == NULL)
 	return FAIL;
@@ -6073,7 +6078,10 @@ compile_lhs(
 	    {
 		p = skip_index(after);
 		if (*p != '[' && *p != '.')
+		{
+		    lhs->lhs_varlen_total = p - var_start;
 		    break;
+		}
 		after = p;
 	    }
 	    if (after > var_start + lhs->lhs_varlen)
@@ -8592,17 +8600,17 @@ compile_substitute(char_u *arg, exarg_T 
 compile_redir(char_u *line, exarg_T *eap, cctx_T *cctx)
 {
     char_u *arg = eap->arg;
-
-    if (cctx->ctx_redir_lhs.lhs_name != NULL)
+    lhs_T	*lhs = &cctx->ctx_redir_lhs;
+
+    if (lhs->lhs_name != NULL)
     {
 	if (STRNCMP(arg, "END", 3) == 0)
 	{
-	    if (cctx->ctx_redir_lhs.lhs_append)
+	    if (lhs->lhs_append)
 	    {
-		if (compile_load_lhs(&cctx->ctx_redir_lhs,
-			     cctx->ctx_redir_lhs.lhs_name, NULL, cctx) == FAIL)
+		if (compile_load_lhs(lhs, lhs->lhs_name, NULL, cctx) == FAIL)
 		    return NULL;
-		if (cctx->ctx_redir_lhs.lhs_has_index)
+		if (lhs->lhs_has_index)
 		    emsg("redir with index not implemented yet");
 	    }
 
@@ -8610,13 +8618,22 @@ compile_redir(char_u *line, exarg_T *eap
 	    // in the variable.
 	    generate_instr_type(cctx, ISN_REDIREND, &t_string);
 
-	    if (cctx->ctx_redir_lhs.lhs_append)
+	    if (lhs->lhs_append)
 		generate_instr_drop(cctx, ISN_CONCAT, 1);
 
-	    if (generate_store_lhs(cctx, &cctx->ctx_redir_lhs, -1) == FAIL)
+	    if (lhs->lhs_has_index)
+	    {
+		// Use the info in "lhs" to store the value at the index in the
+		// list or dict.
+		if (compile_assign_unlet(lhs->lhs_whole, lhs, TRUE,
+						      &t_string, cctx) == FAIL)
+		    return NULL;
+	    }
+	    else if (generate_store_lhs(cctx, lhs, -1) == FAIL)
 		return NULL;
 
-	    VIM_CLEAR(cctx->ctx_redir_lhs.lhs_name);
+	    VIM_CLEAR(lhs->lhs_name);
+	    VIM_CLEAR(lhs->lhs_whole);
 	    return arg + 3;
 	}
 	emsg(_(e_cannot_nest_redir));
@@ -8625,7 +8642,7 @@ compile_redir(char_u *line, exarg_T *eap
 
     if (arg[0] == '=' && arg[1] == '>')
     {
-	int append = FALSE;
+	int	    append = FALSE;
 
 	// redirect to a variable is compiled
 	arg += 2;
@@ -8636,13 +8653,19 @@ compile_redir(char_u *line, exarg_T *eap
 	}
 	arg = skipwhite(arg);
 
-	if (compile_assign_lhs(arg, &cctx->ctx_redir_lhs, CMD_redir,
+	if (compile_assign_lhs(arg, lhs, CMD_redir,
 						FALSE, FALSE, 1, cctx) == FAIL)
 	    return NULL;
 	generate_instr(cctx, ISN_REDIRSTART);
-	cctx->ctx_redir_lhs.lhs_append = append;
-
-	return arg + cctx->ctx_redir_lhs.lhs_varlen;
+	lhs->lhs_append = append;
+	if (lhs->lhs_has_index)
+	{
+	    lhs->lhs_whole = vim_strnsave(arg, lhs->lhs_varlen_total);
+	    if (lhs->lhs_whole == NULL)
+		return NULL;
+	}
+
+	return arg + lhs->lhs_varlen_total;
     }
 
     // other redirects are handled like at script level
@@ -9335,6 +9358,7 @@ erret:
 	    ret = FAIL;
 	}
 	vim_free(cctx.ctx_redir_lhs.lhs_name);
+	vim_free(cctx.ctx_redir_lhs.lhs_whole);
     }
 
     current_sctx = save_current_sctx;