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;
|
int break_ctrl_c;
|
||||||
expand_T xpc;
|
expand_T xpc;
|
||||||
long *b_im_ptr;
|
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;
|
} CommandLineState;
|
||||||
|
|
||||||
typedef struct cmdline_info CmdlineInfo;
|
typedef struct cmdline_info CmdlineInfo;
|
||||||
@ -225,11 +221,19 @@ static bool need_cursor_update = false;
|
|||||||
# include "ex_getln.c.generated.h"
|
# include "ex_getln.c.generated.h"
|
||||||
#endif
|
#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)
|
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;
|
CommandLineState state, *s = &state;
|
||||||
memset(s, 0, sizeof(CommandLineState));
|
memset(s, 0, sizeof(CommandLineState));
|
||||||
s->firstc = firstc;
|
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.prompt_id = last_prompt_id++;
|
||||||
ccline.level++;
|
ccline.level = cmdline_level;
|
||||||
ccline.overstrike = false; // always start in insert mode
|
ccline.overstrike = false; // always start in insert mode
|
||||||
clearpos(&s->match_end);
|
clearpos(&s->match_end);
|
||||||
s->save_cursor = curwin->w_cursor; // may be restored later
|
s->save_cursor = curwin->w_cursor; // may be restored later
|
||||||
@ -489,19 +493,14 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
|
|
||||||
sb_text_end_cmdline();
|
sb_text_end_cmdline();
|
||||||
|
|
||||||
{
|
|
||||||
char_u *p = ccline.cmdbuff;
|
char_u *p = ccline.cmdbuff;
|
||||||
|
|
||||||
// Make ccline empty, getcmdline() may try to use it.
|
|
||||||
ccline.cmdbuff = NULL;
|
|
||||||
|
|
||||||
if (ui_is_external(kUICmdline)) {
|
if (ui_is_external(kUICmdline)) {
|
||||||
ccline.redraw_state = kCmdRedrawNone;
|
|
||||||
ui_call_cmdline_hide(ccline.level);
|
ui_call_cmdline_hide(ccline.level);
|
||||||
}
|
}
|
||||||
ccline.level--;
|
|
||||||
|
cmdline_level--;
|
||||||
return p;
|
return p;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int command_line_check(VimState *state)
|
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_ls = save_p_ls;
|
||||||
p_wmh = save_p_wmh;
|
p_wmh = save_p_wmh;
|
||||||
last_status(false);
|
last_status(false);
|
||||||
save_cmdline(&s->save_ccline);
|
|
||||||
update_screen(VALID); // redraw the screen NOW
|
update_screen(VALID); // redraw the screen NOW
|
||||||
restore_cmdline(&s->save_ccline);
|
|
||||||
redrawcmd();
|
redrawcmd();
|
||||||
save_p_ls = -1;
|
save_p_ls = -1;
|
||||||
wild_menu_showing = 0;
|
wild_menu_showing = 0;
|
||||||
@ -818,18 +815,17 @@ static int command_line_execute(VimState *state, int key)
|
|||||||
new_cmdpos = ccline.cmdpos;
|
new_cmdpos = ccline.cmdpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
save_cmdline(&s->save_ccline);
|
|
||||||
s->c = get_expr_register();
|
s->c = get_expr_register();
|
||||||
restore_cmdline(&s->save_ccline);
|
|
||||||
if (s->c == '=') {
|
if (s->c == '=') {
|
||||||
// Need to save and restore ccline. And set "textlock"
|
// Need to save and restore ccline. And set "textlock"
|
||||||
// to avoid nasty things like going to another buffer when
|
// to avoid nasty things like going to another buffer when
|
||||||
// evaluating an expression.
|
// evaluating an expression.
|
||||||
save_cmdline(&s->save_ccline);
|
CmdlineInfo save_ccline;
|
||||||
++textlock;
|
save_cmdline(&save_ccline);
|
||||||
|
textlock++;
|
||||||
p = get_expr_line();
|
p = get_expr_line();
|
||||||
--textlock;
|
textlock--;
|
||||||
restore_cmdline(&s->save_ccline);
|
restore_cmdline(&save_ccline);
|
||||||
|
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
len = (int)STRLEN(p);
|
len = (int)STRLEN(p);
|
||||||
@ -1362,9 +1358,10 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
beep_flush();
|
beep_flush();
|
||||||
s->c = ESC;
|
s->c = ESC;
|
||||||
} else {
|
} else {
|
||||||
save_cmdline(&s->save_ccline);
|
CmdlineInfo save_ccline;
|
||||||
|
save_cmdline(&save_ccline);
|
||||||
s->c = get_expr_register();
|
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;
|
curwin->w_redr_status = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
save_cmdline(&s->save_ccline);
|
|
||||||
update_screen(SOME_VALID);
|
update_screen(SOME_VALID);
|
||||||
restore_cmdline(&s->save_ccline);
|
|
||||||
restore_last_search_pattern();
|
restore_last_search_pattern();
|
||||||
|
|
||||||
// Leave it at the end to make CTRL-R CTRL-W work.
|
// Leave it at the end to make CTRL-R CTRL-W work.
|
||||||
@ -1996,7 +1991,14 @@ getcmdline (
|
|||||||
int indent // indent for inside conditionals
|
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
|
/// 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;
|
const int msg_col_save = msg_col;
|
||||||
|
|
||||||
struct cmdline_info save_ccline;
|
CmdlineInfo save_ccline;
|
||||||
save_cmdline(&save_ccline);
|
save_cmdline(&save_ccline);
|
||||||
|
|
||||||
ccline.prompt_id = last_prompt_id++;
|
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;
|
int msg_silent_saved = msg_silent;
|
||||||
msg_silent = 0;
|
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);
|
restore_cmdline(&save_ccline);
|
||||||
msg_silent = msg_silent_saved;
|
msg_silent = msg_silent_saved;
|
||||||
@ -2176,6 +2178,7 @@ getexline (
|
|||||||
/* When executing a register, remove ':' that's in front of each line. */
|
/* When executing a register, remove ':' that's in front of each line. */
|
||||||
if (exec_from_reg && vpeekc() == ':')
|
if (exec_from_reg && vpeekc() == ':')
|
||||||
(void)vgetc();
|
(void)vgetc();
|
||||||
|
|
||||||
return getcmdline(c, 1L, indent);
|
return getcmdline(c, 1L, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3019,16 +3022,16 @@ void cmdline_screen_cleared(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int prev_level = ccline.level-1;
|
int prev_level = ccline.level-1;
|
||||||
CmdlineInfo *prev_ccline = ccline.prev_ccline;
|
CmdlineInfo *line = ccline.prev_ccline;
|
||||||
while (prev_level > 0 && prev_ccline) {
|
while (prev_level > 0 && line) {
|
||||||
if (prev_ccline->level == prev_level) {
|
if (line->level == prev_level) {
|
||||||
// don't redraw a cmdline already shown in the cmdline window
|
// don't redraw a cmdline already shown in the cmdline window
|
||||||
if (prev_level != cmdwin_level) {
|
if (prev_level != cmdwin_level) {
|
||||||
prev_ccline->redraw_state = kCmdRedrawAll;
|
line->redraw_state = kCmdRedrawAll;
|
||||||
}
|
}
|
||||||
prev_level--;
|
prev_level--;
|
||||||
}
|
}
|
||||||
prev_ccline = prev_ccline->prev_ccline;
|
line = line->prev_ccline;
|
||||||
}
|
}
|
||||||
|
|
||||||
need_cursor_update = true;
|
need_cursor_update = true;
|
||||||
@ -3244,6 +3247,7 @@ static void save_cmdline(struct cmdline_info *ccp)
|
|||||||
ccline.cmdprompt = NULL;
|
ccline.cmdprompt = NULL;
|
||||||
ccline.xpc = NULL;
|
ccline.xpc = NULL;
|
||||||
ccline.special_char = NUL;
|
ccline.special_char = NUL;
|
||||||
|
ccline.level = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -656,7 +656,6 @@ describe('mappings with <Cmd>', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('works in cmdline mode', function()
|
it('works in cmdline mode', function()
|
||||||
cmdmap('<F2>', 'call setcmdpos(2)')
|
|
||||||
feed(':text<F3>')
|
feed(':text<F3>')
|
||||||
eq('c', eval('m'))
|
eq('c', eval('m'))
|
||||||
-- didn't leave cmdline mode
|
-- didn't leave cmdline mode
|
||||||
@ -768,5 +767,32 @@ describe('mappings with <Cmd>', function()
|
|||||||
|
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user