]> granicus.if.org Git - vim/commitdiff
patch 8.2.1637: Vim9: :put ={expr} does not work inside :def function v8.2.1637
authorBram Moolenaar <Bram@vim.org>
Tue, 8 Sep 2020 20:45:35 +0000 (22:45 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 8 Sep 2020 20:45:35 +0000 (22:45 +0200)
Problem:    Vim9: :put ={expr} does not work inside :def function.
Solution:   Add ISN_PUT. (closes #6397)

12 files changed:
src/edit.c
src/ex_docmd.c
src/mouse.c
src/normal.c
src/proto/register.pro
src/register.c
src/testdir/test_vim9_cmd.vim
src/testdir/test_vim9_disassemble.vim
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index 2cc0ce05cadced30f92e20906448800d619650ed..642ff958bd28d4ff427ecb7056b93a4cace84371 100644 (file)
@@ -3399,7 +3399,7 @@ ins_reg(void)
            AppendCharToRedobuff(literally);
            AppendCharToRedobuff(regname);
 
-           do_put(regname, BACKWARD, 1L,
+           do_put(regname, NULL, BACKWARD, 1L,
                 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
        }
        else if (insert_reg(regname, literally) == FAIL)
@@ -4776,7 +4776,7 @@ ins_pagedown(void)
     static void
 ins_drop(void)
 {
-    do_put('~', BACKWARD, 1L, PUT_CURSEND);
+    do_put('~', NULL, BACKWARD, 1L, PUT_CURSEND);
 }
 #endif
 
index 3dee01d281f39ed141fbea5c2201e383753c3c2c..1d3cfcdcd078e5f8b5c98a0887b8397cd3ee4009 100644 (file)
@@ -7321,7 +7321,7 @@ ex_put(exarg_T *eap)
        eap->forceit = TRUE;
     }
     curwin->w_cursor.lnum = eap->line2;
-    do_put(eap->regname, eap->forceit ? BACKWARD : FORWARD, 1L,
+    do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1L,
                                                       PUT_LINE|PUT_CURSLINE);
 }
 
index 7af90494ffef65428c5e22b9803eac79509b6778..7b1bedc7e1d8e6f597e24c26d7eeea9042bad29c 100644 (file)
@@ -430,7 +430,8 @@ do_mouse(
                    insert_reg(regname, TRUE);
                else
                {
-                   do_put(regname, BACKWARD, 1L, fixindent | PUT_CURSEND);
+                   do_put(regname, NULL, BACKWARD, 1L,
+                                                     fixindent | PUT_CURSEND);
 
                    // Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r
                    AppendCharToRedobuff(Ctrl_R);
@@ -849,7 +850,7 @@ do_mouse(
        // to this position
        if (restart_edit != 0)
            where_paste_started = curwin->w_cursor;
-       do_put(regname, dir, count, fixindent | PUT_CURSEND);
+       do_put(regname, NULL, dir, count, fixindent | PUT_CURSEND);
     }
 
 #if defined(FEAT_QUICKFIX)
index 673cac83e2dd4e100d02c79cd3ffa9c66dbb7d1d..89eaabccc1a62208fce7f0cefd078a2279fa2bad 100644 (file)
@@ -7427,7 +7427,7 @@ nv_put_opt(cmdarg_T *cap, int fix_indent)
            // May have been reset in do_put().
            VIsual_active = TRUE;
        }
-       do_put(cap->oap->regname, dir, cap->count1, flags);
+       do_put(cap->oap->regname, NULL, dir, cap->count1, flags);
 
        // If a register was saved, put it back now.
        if (reg2 != NULL)
@@ -7500,7 +7500,7 @@ nv_nbcmd(cmdarg_T *cap)
     static void
 nv_drop(cmdarg_T *cap UNUSED)
 {
-    do_put('~', BACKWARD, 1L, PUT_CURSEND);
+    do_put('~', NULL, BACKWARD, 1L, PUT_CURSEND);
 }
 #endif
 
index 07a74b352406fc3ed407f347a6f40d2119e3d941..b3a96be7d79a5109e1642e9231800b55e8c3b894 100644 (file)
@@ -27,7 +27,7 @@ void init_yank(void);
 void clear_registers(void);
 void free_yank_all(void);
 int op_yank(oparg_T *oap, int deleting, int mess);
-void do_put(int regname, int dir, long count, int flags);
+void do_put(int regname, char_u *expr_result, int dir, long count, int flags);
 int get_register_name(int num);
 int get_unname_register(void);
 void ex_display(exarg_T *eap);
index 61b6b2c25c7e63ba877b44a16dee87ba0a02935b..ca74aee902a1419f899f4e6688946800e97c0d30 100644 (file)
@@ -1487,6 +1487,7 @@ copy_yank_reg(yankreg_T *reg)
     void
 do_put(
     int                regname,
+    char_u     *expr_result,   // result for regname "=" when compiled
     int                dir,            // BACKWARD for 'P', FORWARD for 'p'
     long       count,
     int                flags)
@@ -1551,11 +1552,12 @@ do_put(
 
     // For special registers '%' (file name), '#' (alternate file name) and
     // ':' (last command line), etc. we have to create a fake yank register.
-    if (get_spec_reg(regname, &insert_string, &allocated, TRUE))
-    {
-       if (insert_string == NULL)
-           return;
-    }
+    // For compiled code "expr_result" holds the expression result.
+    if (regname == '=' && expr_result != NULL)
+       insert_string = expr_result;
+    else if (get_spec_reg(regname, &insert_string, &allocated, TRUE)
+               && insert_string == NULL)
+       return;
 
     // Autocommands may be executed when saving lines for undo.  This might
     // make "y_array" invalid, so we start undo now to avoid that.
index 9372d90952475a6322bd8765cee4c93e63d1d968..4b4e58e9434aaf93a582d958c49581ee390fc0e3 100644 (file)
@@ -315,5 +315,21 @@ def Test_normal_command()
   bwipe!
 enddef
 
+def Test_put_command()
+  new
+  @p = 'ppp'
+  put p
+  assert_equal('ppp', getline(2))
+
+  put ='below'
+  assert_equal('below', getline(3))
+  put! ='above'
+  assert_equal('above', getline(3))
+  assert_equal('below', getline(4))
+
+  bwipe!
+enddef
+
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index b738f193520b77df8e89bafeb3d9e6ce036c7a55..1582f1243f2204908befe2c558832b43ec93ebc6 100644 (file)
@@ -118,6 +118,21 @@ def Test_disassemble_yank_range()
         res)
 enddef
 
+def s:PutExpr()
+  :3put ="text"
+enddef
+
+def Test_disassemble_put_expr()
+  let res = execute('disass s:PutExpr')
+  assert_match('<SNR>\d*_PutExpr.*' ..
+        ' :3put ="text"\_s*' ..
+        '\d PUSHS "text"\_s*' ..
+        '\d PUT = 3\_s*' ..
+        '\d PUSHNR 0\_s*' ..
+        '\d RETURN',
+        res)
+enddef
+
 def s:ScriptFuncPush()
   let localbool = true
   let localspec = v:none
index 874bd709c10296162355a061a341b3dcc3a5a5d5..bad23c572bc016e24a315d2081caf802962d2acd 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1637,
 /**/
     1636,
 /**/
index b7bd84ed5e9a0b29d912c5f76abb03832f982ad9..367c05ce0b56fdc02dce45c4911e4cf6a6344f22 100644 (file)
@@ -135,6 +135,8 @@ typedef enum {
     ISN_CHECKTYPE,  // check value type is isn_arg.type.tc_type
     ISN_CHECKLEN,   // check list length is isn_arg.checklen.cl_min_len
 
+    ISN_PUT,       // ":put", uses isn_arg.put
+
     ISN_SHUFFLE,    // move item on stack up or down
     ISN_DROP       // pop stack and discard value
 } isntype_T;
@@ -261,6 +263,12 @@ typedef struct {
     int                shfl_up;        // places to move upwards
 } shuffle_T;
 
+// arguments to ISN_PUT
+typedef struct {
+    int                put_regname;    // register, can be NUL
+    linenr_T   put_lnum;       // line number to put below
+} put_T;
+
 /*
  * Instruction
  */
@@ -296,6 +304,7 @@ struct isn_S {
        newfunc_T           newfunc;
        checklen_T          checklen;
        shuffle_T           shuffle;
+       put_T               put;
     } isn_arg;
 };
 
index 5893e5ac0bb56fca66bb9016842e00394232baf9..8b1dcd5d572fc42e42b32090528dce8cb5ad8ffe 100644 (file)
@@ -1567,6 +1567,22 @@ generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count)
     return OK;
 }
 
+/*
+ * Generate an ISN_PUT instruction.
+ */
+    static int
+generate_PUT(cctx_T *cctx, int regname, linenr_T lnum)
+{
+    isn_T      *isn;
+
+    RETURN_OK_IF_SKIP(cctx);
+    if ((isn = generate_instr(cctx, ISN_PUT)) == NULL)
+       return FAIL;
+    isn->isn_arg.put.put_regname = regname;
+    isn->isn_arg.put.put_lnum = lnum;
+    return OK;
+}
+
     static int
 generate_EXEC(cctx_T *cctx, char_u *line)
 {
@@ -6271,6 +6287,50 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
     return p;
 }
 
+/*
+ * :put r
+ * :put ={expr}
+ */
+    static char_u *
+compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx)
+{
+    char_u     *line = arg;
+    linenr_T   lnum;
+    char       *errormsg;
+    int                above = FALSE;
+
+    if (*arg == '!')
+    {
+       above = TRUE;
+       line = skipwhite(arg + 1);
+    }
+    eap->regname = *line;
+
+    if (eap->regname == '=')
+    {
+       char_u *p = line + 1;
+
+       if (compile_expr0(&p, cctx) == FAIL)
+           return NULL;
+       line = p;
+    }
+    else if (eap->regname != NUL)
+       ++line;
+
+    // TODO: if the range is something like "$" need to evaluate at runtime
+    if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
+       return NULL;
+    if (eap->addr_count == 0)
+       lnum = -1;
+    else
+       lnum = eap->line2;
+    if (above)
+       --lnum;
+
+    generate_PUT(cctx, eap->regname, lnum);
+    return line;
+}
+
 /*
  * A command that is not compiled, execute with legacy code.
  */
@@ -6870,6 +6930,11 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
                    line = compile_mult_expr(p, ea.cmdidx, &cctx);
                    break;
 
+           case CMD_put:
+                   ea.cmd = cmd;
+                   line = compile_put(p, &ea, &cctx);
+                   break;
+
            // TODO: any other commands with an expression argument?
 
            case CMD_append:
@@ -7192,6 +7257,7 @@ delete_instr(isn_T *isn)
        case ISN_PUSHF:
        case ISN_PUSHNR:
        case ISN_PUSHSPEC:
+       case ISN_PUT:
        case ISN_RETURN:
        case ISN_SHUFFLE:
        case ISN_SLICE:
index 7a2b21d359bb07541f184c4358430224090f71a4..76cafb4c9b92d66d58f8929860b1c5b651f68d0b 100644 (file)
@@ -2581,6 +2581,36 @@ call_def_function(
                }
                break;
 
+           case ISN_PUT:
+               {
+                   int         regname = iptr->isn_arg.put.put_regname;
+                   linenr_T    lnum = iptr->isn_arg.put.put_lnum;
+                   char_u      *expr = NULL;
+                   int         dir = FORWARD;
+
+                   if (regname == '=')
+                   {
+                       tv = STACK_TV_BOT(-1);
+                       if (tv->v_type == VAR_STRING)
+                           expr = tv->vval.v_string;
+                       else
+                       {
+                           expr = typval_tostring(tv);  // allocates value
+                           clear_tv(tv);
+                       }
+                       --ectx.ec_stack.ga_len;
+                   }
+                   if (lnum == -2)
+                       // :put! above cursor
+                       dir = BACKWARD;
+                   else if (lnum >= 0)
+                       curwin->w_cursor.lnum = iptr->isn_arg.put.put_lnum;
+                   check_cursor();
+                   do_put(regname, expr, dir, 1L, PUT_LINE|PUT_CURSLINE);
+                   vim_free(expr);
+               }
+               break;
+
            case ISN_SHUFFLE:
                {
                    typval_T        tmp_tv;
@@ -3227,6 +3257,10 @@ ex_disassemble(exarg_T *eap)
            case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
                                         (long long)(iptr->isn_arg.number));
                              break;
+           case ISN_PUT:
+               smsg("%4d PUT %c %ld", current, iptr->isn_arg.put.put_regname,
+                                            (long)iptr->isn_arg.put.put_lnum);
+               break;
 
            case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
                                         iptr->isn_arg.shuffle.shfl_item,