summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-10-24 23:08:38 +0200
committerBram Moolenaar <Bram@vim.org>2020-10-24 23:08:38 +0200
commit02194d2bd54eacd0b7b9a017a3fe1702ecb80971 (patch)
tree84310e745d3a878f3f239f8dec666bdf1e142021
parent67def64a4e4590a5f3b55ebfc33c42a3dcd7b559 (diff)
patch 8.2.1900: Vim9: command modifiers do not workv8.2.1900
Problem: Vim9: command modifiers do not work. Solution: Make most command modifiers work.
-rw-r--r--src/proto/usercmd.pro3
-rw-r--r--src/scriptfile.c2
-rw-r--r--src/testdir/test_vim9_disassemble.vim8
-rw-r--r--src/usercmd.c140
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h10
-rw-r--r--src/vim9compile.c48
-rw-r--r--src/vim9execute.c61
8 files changed, 161 insertions, 113 deletions
diff --git a/src/proto/usercmd.pro b/src/proto/usercmd.pro
index d7a2a6ad1b..d24e9ad949 100644
--- a/src/proto/usercmd.pro
+++ b/src/proto/usercmd.pro
@@ -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 : */
diff --git a/src/scriptfile.c b/src/scriptfile.c
index 6f447646dc..68d1023f24 100644
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -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);
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index eadac27635..3747ad54d8 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -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)
diff --git a/src/usercmd.c b/src/usercmd.c
index 070e467a67..ac013300fe 100644
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -1235,37 +1235,104 @@ 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).
* "buf" is where the result is to be added.
@@ -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;
}
diff --git a/src/version.c b/src/version.c
index b4c6582556..7aa2e10e62 100644
--- 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 */
/**/
+ 1900,
+/**/
1899,
/**/
1898,
diff --git a/src/vim9.h b/src/vim9.h
index 8056c603f3..60699f994a 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -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;
};
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 7ce55d0e86..60b55d5602 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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;
}
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 759154e01a..10746b1c0d 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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,