1
0
forked from aniani/vim

patch 8.2.1900: Vim9: command modifiers do not work

Problem:    Vim9: command modifiers do not work.
Solution:   Make most command modifiers work.
This commit is contained in:
Bram Moolenaar
2020-10-24 23:08:38 +02:00
parent 67def64a4e
commit 02194d2bd5
8 changed files with 161 additions and 113 deletions

View File

@@ -14,6 +14,7 @@ void ex_command(exarg_T *eap);
void ex_comclear(exarg_T *eap); void ex_comclear(exarg_T *eap);
void uc_clear(garray_T *gap); void uc_clear(garray_T *gap);
void ex_delcommand(exarg_T *eap); 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); void do_ucmd(exarg_T *eap);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@@ -1009,7 +1009,7 @@ ex_options(
int multi_mods = 0; int multi_mods = 0;
buf[0] = NUL; 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); vim_setenv((char_u *)"OPTWIN_CMD", buf);
cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); cmd_source((char_u *)SYS_OPTWIN_FILE, NULL);

View File

@@ -1627,15 +1627,15 @@ def Test_silent()
var res = execute('disass s:SilentMessage') var res = execute('disass s:SilentMessage')
assert_match('<SNR>\d*_SilentMessage\_s*' .. assert_match('<SNR>\d*_SilentMessage\_s*' ..
'silent echomsg "text"\_s*' .. 'silent echomsg "text"\_s*' ..
'\d SILENT\_s*' .. '\d CMDMOD silent\_s*' ..
'\d PUSHS "text"\_s*' .. '\d PUSHS "text"\_s*' ..
'\d ECHOMSG 1\_s*' .. '\d ECHOMSG 1\_s*' ..
'\d UNSILENT\_s*' .. '\d CMDMOD_REV\_s*' ..
'silent! echoerr "error"\_s*' .. 'silent! echoerr "error"\_s*' ..
'\d SILENT!\_s*' .. '\d CMDMOD silent!\_s*' ..
'\d PUSHS "error"\_s*' .. '\d PUSHS "error"\_s*' ..
'\d ECHOERR 1\_s*' .. '\d ECHOERR 1\_s*' ..
'\d UNSILENT!\_s*' .. '\d CMDMOD_REV\_s*' ..
'\d PUSHNR 0\_s*' .. '\d PUSHNR 0\_s*' ..
'\d RETURN', '\d RETURN',
res) res)

View 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. * was added. Return the number of bytes added.
*/ */
size_t 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; size_t result = 0;
// :aboveleft and :leftabove // :aboveleft and :leftabove
if (cmdmod.cmod_split & WSP_ABOVE) if (cmod->cmod_split & WSP_ABOVE)
result += add_cmd_modifier(buf, "aboveleft", multi_mods); result += add_cmd_modifier(buf, "aboveleft", multi_mods);
// :belowright and :rightbelow // :belowright and :rightbelow
if (cmdmod.cmod_split & WSP_BELOW) if (cmod->cmod_split & WSP_BELOW)
result += add_cmd_modifier(buf, "belowright", multi_mods); result += add_cmd_modifier(buf, "belowright", multi_mods);
// :botright // :botright
if (cmdmod.cmod_split & WSP_BOT) if (cmod->cmod_split & WSP_BOT)
result += add_cmd_modifier(buf, "botright", multi_mods); result += add_cmd_modifier(buf, "botright", multi_mods);
// :tab // :tab
if (cmdmod.cmod_tab > 0) if (cmod->cmod_tab > 0)
result += add_cmd_modifier(buf, "tab", multi_mods); result += add_cmd_modifier(buf, "tab", multi_mods);
// :topleft // :topleft
if (cmdmod.cmod_split & WSP_TOP) if (cmod->cmod_split & WSP_TOP)
result += add_cmd_modifier(buf, "topleft", multi_mods); result += add_cmd_modifier(buf, "topleft", multi_mods);
// :vertical // :vertical
if (cmdmod.cmod_split & WSP_VERT) if (cmod->cmod_split & WSP_VERT)
result += add_cmd_modifier(buf, "vertical", multi_mods); result += add_cmd_modifier(buf, "vertical", multi_mods);
return result; 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. * Check for a <> code in a user command.
* "code" points to the '<'. "len" the length of the <> (inclusive). * "code" points to the '<'. "len" the length of the <> (inclusive).
@@ -1452,62 +1519,7 @@ uc_check_code(
case ct_MODS: case ct_MODS:
{ {
int multi_mods = 0; result = produce_cmdmods(buf, &cmdmod, quote);
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 = '"';
}
break; break;
} }

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1900,
/**/ /**/
1899, 1899,
/**/ /**/

View File

@@ -142,8 +142,8 @@ typedef enum {
ISN_PUT, // ":put", uses isn_arg.put ISN_PUT, // ":put", uses isn_arg.put
ISN_SILENT, // set msg_silent or emsg_silent if arg_number is non-zero ISN_CMDMOD, // set cmdmod
ISN_UNSILENT, // undo ISN_SILENT ISN_CMDMOD_REV, // undo ISN_CMDMOD
ISN_SHUFFLE, // move item on stack up or down ISN_SHUFFLE, // move item on stack up or down
ISN_DROP // pop stack and discard value ISN_DROP // pop stack and discard value
@@ -278,6 +278,11 @@ typedef struct {
linenr_T put_lnum; // line number to put below linenr_T put_lnum; // line number to put below
} put_T; } put_T;
// arguments to ISN_CMDMOD
typedef struct {
cmdmod_T *cf_cmdmod; // allocated
} cmod_T;
/* /*
* Instruction * Instruction
*/ */
@@ -314,6 +319,7 @@ struct isn_S {
checklen_T checklen; checklen_T checklen;
shuffle_T shuffle; shuffle_T shuffle;
put_T put; put_T put;
cmod_T cmdmod;
} isn_arg; } isn_arg;
}; };

View File

@@ -142,7 +142,7 @@ struct cctx_S {
garray_T ctx_type_stack; // type of each item on the stack garray_T ctx_type_stack; // type of each item on the stack
garray_T *ctx_type_list; // list of pointers to allocated types 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); 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 static int
generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod) generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod)
{ {
isn_T *isn; isn_T *isn;
// TODO: use more modifiers in the command if (cmod->cmod_flags != 0
if (cmod->cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT)) || 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; return FAIL;
isn->isn_arg.number = (cmod->cmod_flags & CMOD_ERRSILENT) != 0; isn->isn_arg.cmdmod.cf_cmdmod = ALLOC_ONE(cmdmod_T);
cctx->ctx_silent = (cmod->cmod_flags & CMOD_ERRSILENT) ? 2 : 1; if (isn->isn_arg.cmdmod.cf_cmdmod == NULL)
return FAIL;
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; return OK;
} }
static int static int
generate_restore_cmdmods(cctx_T *cctx) generate_undo_cmdmods(cctx_T *cctx)
{ {
isn_T *isn; 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; return FAIL;
isn->isn_arg.number = cctx->ctx_silent == 2;
cctx->ctx_silent = 0;
} }
return OK; return OK;
} }
@@ -7092,9 +7101,9 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
for (;;) for (;;)
{ {
exarg_T ea; exarg_T ea;
cmdmod_T local_cmdmod;
int starts_with_colon = FALSE; int starts_with_colon = FALSE;
char_u *cmd; char_u *cmd;
cmdmod_T local_cmdmod;
// Bail out on the first error to avoid a flood of errors and report // Bail out on the first error to avoid a flood of errors and report
// the right line number when inside try/catch. // 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 * COMMAND MODIFIERS
*/ */
CLEAR_FIELD(local_cmdmod); cctx.ctx_has_cmdmod = FALSE;
if (parse_command_modifiers(&ea, &errormsg, &local_cmdmod, FALSE) if (parse_command_modifiers(&ea, &errormsg, &local_cmdmod, FALSE)
== FAIL) == FAIL)
{ {
@@ -7497,7 +7506,7 @@ nextline:
line = skipwhite(line); line = skipwhite(line);
// Undo any command modifiers. // Undo any command modifiers.
generate_restore_cmdmods(&cctx); generate_undo_cmdmods(&cctx);
if (cctx.ctx_type_stack.ga_len < 0) 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); free_type(isn->isn_arg.type.ct_type);
break; 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_2BOOL:
case ISN_2STRING: case ISN_2STRING:
case ISN_2STRING_ANY: case ISN_2STRING_ANY:
@@ -7754,6 +7769,7 @@ delete_instr(isn_T *isn)
case ISN_CATCH: case ISN_CATCH:
case ISN_CHECKLEN: case ISN_CHECKLEN:
case ISN_CHECKNR: case ISN_CHECKNR:
case ISN_CMDMOD_REV:
case ISN_COMPAREANY: case ISN_COMPAREANY:
case ISN_COMPAREBLOB: case ISN_COMPAREBLOB:
case ISN_COMPAREBOOL: case ISN_COMPAREBOOL:
@@ -7805,7 +7821,6 @@ delete_instr(isn_T *isn)
case ISN_PUT: case ISN_PUT:
case ISN_RETURN: case ISN_RETURN:
case ISN_SHUFFLE: case ISN_SHUFFLE:
case ISN_SILENT:
case ISN_SLICE: case ISN_SLICE:
case ISN_STORE: case ISN_STORE:
case ISN_STOREDICT: case ISN_STOREDICT:
@@ -7819,7 +7834,6 @@ delete_instr(isn_T *isn)
case ISN_STRSLICE: case ISN_STRSLICE:
case ISN_THROW: case ISN_THROW:
case ISN_TRY: case ISN_TRY:
case ISN_UNSILENT:
// nothing allocated // nothing allocated
break; break;
} }

View File

@@ -832,8 +832,8 @@ call_def_function(
int save_suppress_errthrow = suppress_errthrow; int save_suppress_errthrow = suppress_errthrow;
msglist_T **saved_msg_list = NULL; msglist_T **saved_msg_list = NULL;
msglist_T *private_msg_list = NULL; msglist_T *private_msg_list = NULL;
int save_msg_silent = -1; cmdmod_T save_cmdmod;
int save_emsg_silent = -1; int restore_cmdmod = FALSE;
// Get pointer to item in the stack. // Get pointer to item in the stack.
#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
@@ -2816,22 +2816,19 @@ call_def_function(
} }
break; break;
case ISN_SILENT: case ISN_CMDMOD:
if (save_msg_silent == -1) save_cmdmod = cmdmod;
save_msg_silent = msg_silent; restore_cmdmod = TRUE;
++msg_silent; cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod;
if (iptr->isn_arg.number) apply_cmdmod(&cmdmod);
{
if (save_emsg_silent == -1)
save_emsg_silent = emsg_silent;
++emsg_silent;
}
break; break;
case ISN_UNSILENT: case ISN_CMDMOD_REV:
--msg_silent; // filter regprog is owned by the instruction, don't free it
if (iptr->isn_arg.number) cmdmod.cmod_filter_regmatch.regprog = NULL;
--emsg_silent; undo_cmdmod(&cmdmod);
cmdmod = save_cmdmod;
restore_cmdmod = FALSE;
break; break;
case ISN_SHUFFLE: case ISN_SHUFFLE:
@@ -2905,10 +2902,12 @@ failed:
} }
msg_list = saved_msg_list; msg_list = saved_msg_list;
if (save_msg_silent != -1) if (restore_cmdmod)
msg_silent = save_msg_silent; {
if (save_emsg_silent != -1) cmdmod.cmod_filter_regmatch.regprog = NULL;
emsg_silent = save_emsg_silent; undo_cmdmod(&cmdmod);
cmdmod = save_cmdmod;
}
failed_early: failed_early:
// Free all local variables, but not arguments. // Free all local variables, but not arguments.
@@ -3527,10 +3526,24 @@ ex_disassemble(exarg_T *eap)
(long)iptr->isn_arg.put.put_lnum); (long)iptr->isn_arg.put.put_lnum);
break; break;
case ISN_SILENT: smsg("%4d SILENT%s", current, // TODO: summarize modifiers
iptr->isn_arg.number ? "!" : ""); break; case ISN_CMDMOD:
case ISN_UNSILENT: smsg("%4d UNSILENT%s", current, {
iptr->isn_arg.number ? "!" : ""); break; 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, case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
iptr->isn_arg.shuffle.shfl_item, iptr->isn_arg.shuffle.shfl_item,