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:
@@ -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 : */
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
140
src/usercmd.c
140
src/usercmd.c
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -750,6 +750,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1900,
|
||||
/**/
|
||||
1899,
|
||||
/**/
|
||||
|
10
src/vim9.h
10
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;
|
||||
};
|
||||
|
||||
|
@@ -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.number = (cmod->cmod_flags & CMOD_ERRSILENT) != 0;
|
||||
cctx->ctx_silent = (cmod->cmod_flags & CMOD_ERRSILENT) ? 2 : 1;
|
||||
isn->isn_arg.cmdmod.cf_cmdmod = ALLOC_ONE(cmdmod_T);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user