]> granicus.if.org Git - vim/commitdiff
patch 8.2.1900: Vim9: command modifiers do not work v8.2.1900
authorBram Moolenaar <Bram@vim.org>
Sat, 24 Oct 2020 21:08:38 +0000 (23:08 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 24 Oct 2020 21:08:38 +0000 (23:08 +0200)
Problem:    Vim9: command modifiers do not work.
Solution:   Make most command modifiers work.

src/proto/usercmd.pro
src/scriptfile.c
src/testdir/test_vim9_disassemble.vim
src/usercmd.c
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index d7a2a6ad1b708b808ca9ecd349057e181a29cc5c..d24e9ad9498eefc3cf55279aef3269821df47f61 100644 (file)
@@ -14,6 +14,7 @@ void ex_command(exarg_T *eap);
 void ex_comclear(exarg_T *eap);
 void uc_clear(garray_T *gap);
 void ex_delcommand(exarg_T *eap);
-size_t add_win_cmd_modifers(char_u *buf, int *multi_mods);
+size_t add_win_cmd_modifers(char_u *buf, cmdmod_T *cmod, int *multi_mods);
+int produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote);
 void do_ucmd(exarg_T *eap);
 /* vim: set ft=c : */
index 6f447646dcc51bacf28feb340194a4ca02c79646..68d1023f24557aaf3450685c5da8e08cdbbb2652 100644 (file)
@@ -1009,7 +1009,7 @@ ex_options(
     int            multi_mods = 0;
 
     buf[0] = NUL;
-    (void)add_win_cmd_modifers(buf, &multi_mods);
+    (void)add_win_cmd_modifers(buf, &cmdmod, &multi_mods);
 
     vim_setenv((char_u *)"OPTWIN_CMD", buf);
     cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);
index eadac2763541ae8db032f4efba3b74b41a6325a9..3747ad54d8f02620e73c3b99ce6cae79e99b0afd 100644 (file)
@@ -1627,15 +1627,15 @@ def Test_silent()
   var res = execute('disass s:SilentMessage')
   assert_match('<SNR>\d*_SilentMessage\_s*' ..
         'silent echomsg "text"\_s*' ..
-        '\d SILENT\_s*' ..
+        '\d CMDMOD silent\_s*' ..
         '\d PUSHS "text"\_s*' ..
         '\d ECHOMSG 1\_s*' ..
-        '\d UNSILENT\_s*' ..
+        '\d CMDMOD_REV\_s*' ..
         'silent! echoerr "error"\_s*' ..
-        '\d SILENT!\_s*' ..
+        '\d CMDMOD silent!\_s*' ..
         '\d PUSHS "error"\_s*' ..
         '\d ECHOERR 1\_s*' ..
-        '\d UNSILENT!\_s*' ..
+        '\d CMDMOD_REV\_s*' ..
         '\d PUSHNR 0\_s*' ..
         '\d RETURN',
         res)
index 070e467a6734fa7c0555f405a122871cd035601d..ac013300fe2ae8af371f5d9771f3b322d88fbcd4 100644 (file)
@@ -1235,36 +1235,103 @@ add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods)
 }
 
 /*
- * Add modifiers from "cmdmod.cmod_split" to "buf".  Set "multi_mods" when one
+ * Add modifiers from "cmod->cmod_split" to "buf".  Set "multi_mods" when one
  * was added.  Return the number of bytes added.
  */
     size_t
-add_win_cmd_modifers(char_u *buf, int *multi_mods)
+add_win_cmd_modifers(char_u *buf, cmdmod_T *cmod, int *multi_mods)
 {
     size_t result = 0;
 
     // :aboveleft and :leftabove
-    if (cmdmod.cmod_split & WSP_ABOVE)
+    if (cmod->cmod_split & WSP_ABOVE)
        result += add_cmd_modifier(buf, "aboveleft", multi_mods);
     // :belowright and :rightbelow
-    if (cmdmod.cmod_split & WSP_BELOW)
+    if (cmod->cmod_split & WSP_BELOW)
        result += add_cmd_modifier(buf, "belowright", multi_mods);
     // :botright
-    if (cmdmod.cmod_split & WSP_BOT)
+    if (cmod->cmod_split & WSP_BOT)
        result += add_cmd_modifier(buf, "botright", multi_mods);
 
     // :tab
-    if (cmdmod.cmod_tab > 0)
+    if (cmod->cmod_tab > 0)
        result += add_cmd_modifier(buf, "tab", multi_mods);
     // :topleft
-    if (cmdmod.cmod_split & WSP_TOP)
+    if (cmod->cmod_split & WSP_TOP)
        result += add_cmd_modifier(buf, "topleft", multi_mods);
     // :vertical
-    if (cmdmod.cmod_split & WSP_VERT)
+    if (cmod->cmod_split & WSP_VERT)
        result += add_cmd_modifier(buf, "vertical", multi_mods);
     return result;
 }
 
+/*
+ * Generate text for the "cmod" command modifiers.
+ * If "buf" is NULL just return the length.
+ */
+    int
+produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote)
+{
+    int            result = 0;
+    int            multi_mods = 0;
+    int            i;
+    typedef struct {
+       int flag;
+       char *name;
+    } mod_entry_T;
+    static mod_entry_T mod_entries[] = {
+#ifdef FEAT_BROWSE_CMD
+       {CMOD_BROWSE, "browse"},
+#endif
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+       {CMOD_CONFIRM, "confirm"},
+#endif
+       {CMOD_HIDE, "hide"},
+       {CMOD_KEEPALT, "keepalt"},
+       {CMOD_KEEPJUMPS, "keepjumps"},
+       {CMOD_KEEPMARKS, "keepmarks"},
+       {CMOD_KEEPPATTERNS, "keeppatterns"},
+       {CMOD_LOCKMARKS, "lockmarks"},
+       {CMOD_NOSWAPFILE, "noswapfile"},
+       {CMOD_UNSILENT, "unsilent"},
+       {CMOD_NOAUTOCMD, "noautocmd"},
+#ifdef HAVE_SANDBOX
+       {CMOD_SANDBOX, "sandbox"},
+#endif
+       {0, NULL}
+    };
+
+    result = quote ? 2 : 0;
+    if (buf != NULL)
+    {
+       if (quote)
+           *buf++ = '"';
+       *buf = '\0';
+    }
+
+    // the modifiers that are simple flags
+    for (i = 0; mod_entries[i].name != NULL; ++i)
+       if (cmod->cmod_flags & mod_entries[i].flag)
+           result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods);
+
+    // :silent
+    if (cmod->cmod_flags & CMOD_SILENT)
+       result += add_cmd_modifier(buf,
+                       (cmod->cmod_flags & CMOD_ERRSILENT) ? "silent!"
+                                                     : "silent", &multi_mods);
+    // :verbose
+    if (p_verbose > 0)
+       result += add_cmd_modifier(buf, "verbose", &multi_mods);
+    // flags from cmod->cmod_split
+    result += add_win_cmd_modifers(buf, cmod, &multi_mods);
+    if (quote && buf != NULL)
+    {
+       buf += result - 2;
+       *buf = '"';
+    }
+    return result;
+}
+
 /*
  * Check for a <> code in a user command.
  * "code" points to the '<'.  "len" the length of the <> (inclusive).
@@ -1452,62 +1519,7 @@ uc_check_code(
 
     case ct_MODS:
     {
-       int multi_mods = 0;
-       typedef struct {
-           int flag;
-           char *name;
-       } mod_entry_T;
-       static mod_entry_T mod_entries[] = {
-#ifdef FEAT_BROWSE_CMD
-           {CMOD_BROWSE, "browse"},
-#endif
-#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-           {CMOD_CONFIRM, "confirm"},
-#endif
-           {CMOD_HIDE, "hide"},
-           {CMOD_KEEPALT, "keepalt"},
-           {CMOD_KEEPJUMPS, "keepjumps"},
-           {CMOD_KEEPMARKS, "keepmarks"},
-           {CMOD_KEEPPATTERNS, "keeppatterns"},
-           {CMOD_LOCKMARKS, "lockmarks"},
-           {CMOD_NOSWAPFILE, "noswapfile"},
-           {0, NULL}
-       };
-       int i;
-
-       result = quote ? 2 : 0;
-       if (buf != NULL)
-       {
-           if (quote)
-               *buf++ = '"';
-           *buf = '\0';
-       }
-
-       // the modifiers that are simple flags
-       for (i = 0; mod_entries[i].name != NULL; ++i)
-           if (cmdmod.cmod_flags & mod_entries[i].flag)
-               result += add_cmd_modifier(buf, mod_entries[i].name,
-                                                                &multi_mods);
-
-       // TODO: How to support :noautocmd?
-#ifdef HAVE_SANDBOX
-       // TODO: How to support :sandbox?
-#endif
-       // :silent
-       if (msg_silent > 0)
-           result += add_cmd_modifier(buf,
-                   emsg_silent > 0 ? "silent!" : "silent", &multi_mods);
-       // TODO: How to support :unsilent?
-       // :verbose
-       if (p_verbose > 0)
-           result += add_cmd_modifier(buf, "verbose", &multi_mods);
-       // flags from cmdmod.cmod_split
-       result += add_win_cmd_modifers(buf, &multi_mods);
-       if (quote && buf != NULL)
-       {
-           buf += result - 2;
-           *buf = '"';
-       }
+       result = produce_cmdmods(buf, &cmdmod, quote);
        break;
     }
 
index b4c658255637a6e2ffa43e3f8d20ea20fdb99418..7aa2e10e6243ca3b33e220071a0df485fad87ba9 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1900,
 /**/
     1899,
 /**/
index 8056c603f3c5b15515d1555526ee25f346fab51e..60699f994ab38c73311a235dbbd91a88fd8bfe21 100644 (file)
@@ -142,8 +142,8 @@ typedef enum {
 
     ISN_PUT,       // ":put", uses isn_arg.put
 
-    ISN_SILENT,            // set msg_silent or emsg_silent if arg_number is non-zero
-    ISN_UNSILENT,   // undo ISN_SILENT
+    ISN_CMDMOD,            // set cmdmod
+    ISN_CMDMOD_REV, // undo ISN_CMDMOD
 
     ISN_SHUFFLE,    // move item on stack up or down
     ISN_DROP       // pop stack and discard value
@@ -278,6 +278,11 @@ typedef struct {
     linenr_T   put_lnum;       // line number to put below
 } put_T;
 
+// arguments to ISN_CMDMOD
+typedef struct {
+    cmdmod_T   *cf_cmdmod;     // allocated
+} cmod_T;
+
 /*
  * Instruction
  */
@@ -314,6 +319,7 @@ struct isn_S {
        checklen_T          checklen;
        shuffle_T           shuffle;
        put_T               put;
+       cmod_T              cmdmod;
     } isn_arg;
 };
 
index 7ce55d0e867f7c4d9f3f8c5be0239b848882f1f1..60b55d560230d5baa41e2ec01e0cd396be60e8ce 100644 (file)
@@ -142,7 +142,7 @@ struct cctx_S {
     garray_T   ctx_type_stack;     // type of each item on the stack
     garray_T   *ctx_type_list;     // list of pointers to allocated types
 
-    int                ctx_silent;         // set when ISN_SILENT was generated
+    int                ctx_has_cmdmod;     // ISN_CMDMOD was generated
 };
 
 static void delete_def_function_contents(dfunc_T *dfunc);
@@ -1823,36 +1823,45 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
 }
 
 /*
- * Generate any instructions for side effects of "cmdmod".
+ * Generate an instruction for any command modifiers.
  */
     static int
 generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod)
 {
     isn_T      *isn;
 
-    // TODO: use more modifiers in the command
-    if (cmod->cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT))
+    if (cmod->cmod_flags != 0
+           || cmod->cmod_split != 0
+           || cmod->cmod_verbose != 0
+           || cmod->cmod_tab != 0
+           || cmod->cmod_filter_regmatch.regprog != NULL)
     {
-       if ((isn = generate_instr(cctx, ISN_SILENT)) == NULL)
+       cctx->ctx_has_cmdmod = TRUE;
+
+       if ((isn = generate_instr(cctx, ISN_CMDMOD)) == NULL)
+           return FAIL;
+       isn->isn_arg.cmdmod.cf_cmdmod = ALLOC_ONE(cmdmod_T);
+       if (isn->isn_arg.cmdmod.cf_cmdmod == NULL)
            return FAIL;
-       isn->isn_arg.number = (cmod->cmod_flags & CMOD_ERRSILENT) != 0;
-       cctx->ctx_silent = (cmod->cmod_flags & CMOD_ERRSILENT) ? 2 : 1;
+       mch_memmove(isn->isn_arg.cmdmod.cf_cmdmod, cmod, sizeof(cmdmod_T));
+       // filter progam now belongs to the instruction
+       cmod->cmod_filter_regmatch.regprog = NULL;
     }
+
     return OK;
 }
 
     static int
-generate_restore_cmdmods(cctx_T *cctx)
+generate_undo_cmdmods(cctx_T *cctx)
 {
     isn_T      *isn;
 
-    if (cctx->ctx_silent > 0)
+    if (cctx->ctx_has_cmdmod)
     {
-       if ((isn = generate_instr(cctx, ISN_UNSILENT)) == NULL)
+       if ((isn = generate_instr(cctx, ISN_CMDMOD_REV)) == NULL)
            return FAIL;
-       isn->isn_arg.number = cctx->ctx_silent == 2;
-       cctx->ctx_silent = 0;
     }
+
     return OK;
 }
 
@@ -7092,9 +7101,9 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
     for (;;)
     {
        exarg_T     ea;
-       cmdmod_T    local_cmdmod;
        int         starts_with_colon = FALSE;
        char_u      *cmd;
+       cmdmod_T    local_cmdmod;
 
        // Bail out on the first error to avoid a flood of errors and report
        // the right line number when inside try/catch.
@@ -7175,7 +7184,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
        /*
         * COMMAND MODIFIERS
         */
-       CLEAR_FIELD(local_cmdmod);
+       cctx.ctx_has_cmdmod = FALSE;
        if (parse_command_modifiers(&ea, &errormsg, &local_cmdmod, FALSE)
                                                                       == FAIL)
        {
@@ -7497,7 +7506,7 @@ nextline:
        line = skipwhite(line);
 
        // Undo any command modifiers.
-       generate_restore_cmdmods(&cctx);
+       generate_undo_cmdmods(&cctx);
 
        if (cctx.ctx_type_stack.ga_len < 0)
        {
@@ -7742,6 +7751,12 @@ delete_instr(isn_T *isn)
            free_type(isn->isn_arg.type.ct_type);
            break;
 
+       case ISN_CMDMOD:
+           vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod
+                                              ->cmod_filter_regmatch.regprog);
+           vim_free(isn->isn_arg.cmdmod.cf_cmdmod);
+           break;
+
        case ISN_2BOOL:
        case ISN_2STRING:
        case ISN_2STRING_ANY:
@@ -7754,6 +7769,7 @@ delete_instr(isn_T *isn)
        case ISN_CATCH:
        case ISN_CHECKLEN:
        case ISN_CHECKNR:
+       case ISN_CMDMOD_REV:
        case ISN_COMPAREANY:
        case ISN_COMPAREBLOB:
        case ISN_COMPAREBOOL:
@@ -7805,7 +7821,6 @@ delete_instr(isn_T *isn)
        case ISN_PUT:
        case ISN_RETURN:
        case ISN_SHUFFLE:
-       case ISN_SILENT:
        case ISN_SLICE:
        case ISN_STORE:
        case ISN_STOREDICT:
@@ -7819,7 +7834,6 @@ delete_instr(isn_T *isn)
        case ISN_STRSLICE:
        case ISN_THROW:
        case ISN_TRY:
-       case ISN_UNSILENT:
            // nothing allocated
            break;
     }
index 759154e01ace6cc11113b9595fd29cd79ef9c9b6..10746b1c0dae02904654241fadb4d360d53a6287 100644 (file)
@@ -832,8 +832,8 @@ call_def_function(
     int                save_suppress_errthrow = suppress_errthrow;
     msglist_T  **saved_msg_list = NULL;
     msglist_T  *private_msg_list = NULL;
-    int                save_msg_silent = -1;
-    int                save_emsg_silent = -1;
+    cmdmod_T   save_cmdmod;
+    int                restore_cmdmod = FALSE;
 
 // Get pointer to item in the stack.
 #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
@@ -2816,22 +2816,19 @@ call_def_function(
                }
                break;
 
-           case ISN_SILENT:
-               if (save_msg_silent == -1)
-                   save_msg_silent = msg_silent;
-               ++msg_silent;
-               if (iptr->isn_arg.number)
-               {
-                   if (save_emsg_silent == -1)
-                       save_emsg_silent = emsg_silent;
-                   ++emsg_silent;
-               }
+           case ISN_CMDMOD:
+               save_cmdmod = cmdmod;
+               restore_cmdmod = TRUE;
+               cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod;
+               apply_cmdmod(&cmdmod);
                break;
 
-           case ISN_UNSILENT:
-               --msg_silent;
-               if (iptr->isn_arg.number)
-                   --emsg_silent;
+           case ISN_CMDMOD_REV:
+               // filter regprog is owned by the instruction, don't free it
+               cmdmod.cmod_filter_regmatch.regprog = NULL;
+               undo_cmdmod(&cmdmod);
+               cmdmod = save_cmdmod;
+               restore_cmdmod = FALSE;
                break;
 
            case ISN_SHUFFLE:
@@ -2905,10 +2902,12 @@ failed:
     }
     msg_list = saved_msg_list;
 
-    if (save_msg_silent != -1)
-       msg_silent = save_msg_silent;
-    if (save_emsg_silent != -1)
-       emsg_silent = save_emsg_silent;
+    if (restore_cmdmod)
+    {
+       cmdmod.cmod_filter_regmatch.regprog = NULL;
+       undo_cmdmod(&cmdmod);
+       cmdmod = save_cmdmod;
+    }
 
 failed_early:
     // Free all local variables, but not arguments.
@@ -3527,10 +3526,24 @@ ex_disassemble(exarg_T *eap)
                                             (long)iptr->isn_arg.put.put_lnum);
                break;
 
-           case ISN_SILENT: smsg("%4d SILENT%s", current,
-                                      iptr->isn_arg.number ? "!" : ""); break;
-           case ISN_UNSILENT: smsg("%4d UNSILENT%s", current,
-                                      iptr->isn_arg.number ? "!" : ""); break;
+               // TODO: summarize modifiers
+           case ISN_CMDMOD:
+               {
+                   char_u  *buf;
+                   int     len = produce_cmdmods(
+                                 NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);
+
+                   buf = alloc(len + 1);
+                   if (buf != NULL)
+                   {
+                       (void)produce_cmdmods(
+                                  buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE);
+                       smsg("%4d CMDMOD %s", current, buf);
+                       vim_free(buf);
+                   }
+                   break;
+               }
+           case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break;
 
            case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
                                         iptr->isn_arg.shuffle.shfl_item,