mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #8859 from bfredl/cmdline_norm
cmdline: always use save_cmdline before command_line_enter
This commit is contained in:
commit
c7db42faab
@ -177,10 +177,6 @@ typedef struct command_line_state {
|
||||
int break_ctrl_c;
|
||||
expand_T xpc;
|
||||
long *b_im_ptr;
|
||||
// Everything that may work recursively should save and restore the
|
||||
// current command line in save_ccline. That includes update_screen(), a
|
||||
// custom status line may invoke ":normal".
|
||||
struct cmdline_info save_ccline;
|
||||
} CommandLineState;
|
||||
|
||||
typedef struct cmdline_info CmdlineInfo;
|
||||
@ -225,11 +221,19 @@ static bool need_cursor_update = false;
|
||||
# include "ex_getln.c.generated.h"
|
||||
#endif
|
||||
|
||||
static int cmd_hkmap = 0; /* Hebrew mapping during command line */
|
||||
static int cmd_hkmap = 0; // Hebrew mapping during command line
|
||||
static int cmd_fkmap = 0; // Farsi mapping during command line
|
||||
|
||||
static int cmd_fkmap = 0; /* Farsi mapping during command line */
|
||||
/// Internal entry point for cmdline mode.
|
||||
///
|
||||
/// caller must use save_cmdline and restore_cmdline. Best is to use
|
||||
/// getcmdline or getcmdline_prompt, instead of calling this directly.
|
||||
static uint8_t *command_line_enter(int firstc, long count, int indent)
|
||||
{
|
||||
// can be invoked recursively, identify each level
|
||||
static int cmdline_level = 0;
|
||||
cmdline_level++;
|
||||
|
||||
CommandLineState state, *s = &state;
|
||||
memset(s, 0, sizeof(CommandLineState));
|
||||
s->firstc = firstc;
|
||||
@ -257,7 +261,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
||||
}
|
||||
|
||||
ccline.prompt_id = last_prompt_id++;
|
||||
ccline.level++;
|
||||
ccline.level = cmdline_level;
|
||||
ccline.overstrike = false; // always start in insert mode
|
||||
clearpos(&s->match_end);
|
||||
s->save_cursor = curwin->w_cursor; // may be restored later
|
||||
@ -489,20 +493,15 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
||||
|
||||
sb_text_end_cmdline();
|
||||
|
||||
{
|
||||
char_u *p = ccline.cmdbuff;
|
||||
|
||||
// Make ccline empty, getcmdline() may try to use it.
|
||||
ccline.cmdbuff = NULL;
|
||||
|
||||
if (ui_is_external(kUICmdline)) {
|
||||
ccline.redraw_state = kCmdRedrawNone;
|
||||
ui_call_cmdline_hide(ccline.level);
|
||||
}
|
||||
ccline.level--;
|
||||
|
||||
cmdline_level--;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
static int command_line_check(VimState *state)
|
||||
{
|
||||
@ -641,9 +640,7 @@ static int command_line_execute(VimState *state, int key)
|
||||
p_ls = save_p_ls;
|
||||
p_wmh = save_p_wmh;
|
||||
last_status(false);
|
||||
save_cmdline(&s->save_ccline);
|
||||
update_screen(VALID); // redraw the screen NOW
|
||||
restore_cmdline(&s->save_ccline);
|
||||
redrawcmd();
|
||||
save_p_ls = -1;
|
||||
wild_menu_showing = 0;
|
||||
@ -818,18 +815,17 @@ static int command_line_execute(VimState *state, int key)
|
||||
new_cmdpos = ccline.cmdpos;
|
||||
}
|
||||
|
||||
save_cmdline(&s->save_ccline);
|
||||
s->c = get_expr_register();
|
||||
restore_cmdline(&s->save_ccline);
|
||||
if (s->c == '=') {
|
||||
// Need to save and restore ccline. And set "textlock"
|
||||
// to avoid nasty things like going to another buffer when
|
||||
// evaluating an expression.
|
||||
save_cmdline(&s->save_ccline);
|
||||
++textlock;
|
||||
CmdlineInfo save_ccline;
|
||||
save_cmdline(&save_ccline);
|
||||
textlock++;
|
||||
p = get_expr_line();
|
||||
--textlock;
|
||||
restore_cmdline(&s->save_ccline);
|
||||
textlock--;
|
||||
restore_cmdline(&save_ccline);
|
||||
|
||||
if (p != NULL) {
|
||||
len = (int)STRLEN(p);
|
||||
@ -1362,9 +1358,10 @@ static int command_line_handle_key(CommandLineState *s)
|
||||
beep_flush();
|
||||
s->c = ESC;
|
||||
} else {
|
||||
save_cmdline(&s->save_ccline);
|
||||
CmdlineInfo save_ccline;
|
||||
save_cmdline(&save_ccline);
|
||||
s->c = get_expr_register();
|
||||
restore_cmdline(&s->save_ccline);
|
||||
restore_cmdline(&save_ccline);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1899,9 +1896,7 @@ static int command_line_changed(CommandLineState *s)
|
||||
curwin->w_redr_status = true;
|
||||
}
|
||||
|
||||
save_cmdline(&s->save_ccline);
|
||||
update_screen(SOME_VALID);
|
||||
restore_cmdline(&s->save_ccline);
|
||||
restore_last_search_pattern();
|
||||
|
||||
// Leave it at the end to make CTRL-R CTRL-W work.
|
||||
@ -1996,7 +1991,14 @@ getcmdline (
|
||||
int indent // indent for inside conditionals
|
||||
)
|
||||
{
|
||||
return command_line_enter(firstc, count, indent);
|
||||
// Be prepared for situations where cmdline can be invoked recursively.
|
||||
// That includes cmd mappings, event handlers, as well as update_screen()
|
||||
// (custom status line eval), which all may invoke ":normal :".
|
||||
CmdlineInfo save_ccline;
|
||||
save_cmdline(&save_ccline);
|
||||
char_u *retval = command_line_enter(firstc, count, indent);
|
||||
restore_cmdline(&save_ccline);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// Get a command line with a prompt
|
||||
@ -2020,7 +2022,7 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
|
||||
{
|
||||
const int msg_col_save = msg_col;
|
||||
|
||||
struct cmdline_info save_ccline;
|
||||
CmdlineInfo save_ccline;
|
||||
save_cmdline(&save_ccline);
|
||||
|
||||
ccline.prompt_id = last_prompt_id++;
|
||||
@ -2034,7 +2036,7 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
|
||||
int msg_silent_saved = msg_silent;
|
||||
msg_silent = 0;
|
||||
|
||||
char *const ret = (char *)getcmdline(firstc, 1L, 0);
|
||||
char *const ret = (char *)command_line_enter(firstc, 1L, 0);
|
||||
|
||||
restore_cmdline(&save_ccline);
|
||||
msg_silent = msg_silent_saved;
|
||||
@ -2176,6 +2178,7 @@ getexline (
|
||||
/* When executing a register, remove ':' that's in front of each line. */
|
||||
if (exec_from_reg && vpeekc() == ':')
|
||||
(void)vgetc();
|
||||
|
||||
return getcmdline(c, 1L, indent);
|
||||
}
|
||||
|
||||
@ -3019,16 +3022,16 @@ void cmdline_screen_cleared(void)
|
||||
}
|
||||
|
||||
int prev_level = ccline.level-1;
|
||||
CmdlineInfo *prev_ccline = ccline.prev_ccline;
|
||||
while (prev_level > 0 && prev_ccline) {
|
||||
if (prev_ccline->level == prev_level) {
|
||||
CmdlineInfo *line = ccline.prev_ccline;
|
||||
while (prev_level > 0 && line) {
|
||||
if (line->level == prev_level) {
|
||||
// don't redraw a cmdline already shown in the cmdline window
|
||||
if (prev_level != cmdwin_level) {
|
||||
prev_ccline->redraw_state = kCmdRedrawAll;
|
||||
line->redraw_state = kCmdRedrawAll;
|
||||
}
|
||||
prev_level--;
|
||||
}
|
||||
prev_ccline = prev_ccline->prev_ccline;
|
||||
line = line->prev_ccline;
|
||||
}
|
||||
|
||||
need_cursor_update = true;
|
||||
@ -3244,6 +3247,7 @@ static void save_cmdline(struct cmdline_info *ccp)
|
||||
ccline.cmdprompt = NULL;
|
||||
ccline.xpc = NULL;
|
||||
ccline.special_char = NUL;
|
||||
ccline.level = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -656,7 +656,6 @@ describe('mappings with <Cmd>', function()
|
||||
end)
|
||||
|
||||
it('works in cmdline mode', function()
|
||||
cmdmap('<F2>', 'call setcmdpos(2)')
|
||||
feed(':text<F3>')
|
||||
eq('c', eval('m'))
|
||||
-- didn't leave cmdline mode
|
||||
@ -768,5 +767,32 @@ describe('mappings with <Cmd>', function()
|
||||
|
||||
end)
|
||||
|
||||
it("doesn't crash when invoking cmdline mode recursively #8859", function()
|
||||
cmdmap('<F2>', 'norm! :foo')
|
||||
feed(':bar')
|
||||
screen:expect([[
|
||||
some short lines |
|
||||
of test text |
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
:bar^ |
|
||||
]])
|
||||
|
||||
feed('<f2>x')
|
||||
screen:expect([[
|
||||
some short lines |
|
||||
of test text |
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
{1:~ }|
|
||||
:barx^ |
|
||||
]])
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user