vim-patch:8.0.1139: using window toolbar changes state

Problem:    Using window toolbar changes state.
Solution:   Always execute window toolbar actions in Normal mode.
a21a6a9ade
This commit is contained in:
Jan Edmund Lazo
2020-03-14 12:47:49 -04:00
parent 86d0f67c29
commit 5b3ec39df3
5 changed files with 105 additions and 56 deletions

View File

@@ -334,7 +334,7 @@ typedef struct {
// Struct to hold the saved typeahead for save_typeahead().
typedef struct {
typebuf_T save_typebuf;
int typebuf_valid; // TRUE when save_typebuf valid
bool typebuf_valid; // true when save_typebuf valid
int old_char;
int old_mod_mask;
buffheader_T save_readbuf1;

View File

@@ -8209,6 +8209,57 @@ void update_topline_cursor(void)
update_curswant();
}
// Save the current State and go to Normal mode.
// Return true if the typeahead could be saved.
bool save_current_state(save_state_T *sst)
FUNC_ATTR_NONNULL_ALL
{
sst->save_msg_scroll = msg_scroll;
sst->save_restart_edit = restart_edit;
sst->save_msg_didout = msg_didout;
sst->save_State = State;
sst->save_insertmode = p_im;
sst->save_finish_op = finish_op;
sst->save_opcount = opcount;
sst->save_reg_executing = reg_executing;
msg_scroll = false; // no msg scrolling in Normal mode
restart_edit = 0; // don't go to Insert mode
p_im = false; // don't use 'insertmode
// Save the current typeahead. This is required to allow using ":normal"
// from an event handler and makes sure we don't hang when the argument
// ends with half a command.
save_typeahead(&sst->tabuf);
return sst->tabuf.typebuf_valid;
}
void restore_current_state(save_state_T *sst)
FUNC_ATTR_NONNULL_ALL
{
// Restore the previous typeahead.
restore_typeahead(&sst->tabuf);
msg_scroll = sst->save_msg_scroll;
if (force_restart_edit) {
force_restart_edit = false;
} else {
// Some function (terminal_enter()) was aware of ex_normal and decided to
// override the value of restart_edit anyway.
restart_edit = sst->save_restart_edit;
}
p_im = sst->save_insertmode;
finish_op = sst->save_finish_op;
opcount = sst->save_opcount;
reg_executing = sst->save_reg_executing;
msg_didout |= sst->save_msg_didout; // don't reset msg_didout now
// Restore the state (needed when called from a function executed for
// 'indentexpr'). Update the mouse and cursor, they may have changed.
State = sst->save_State;
ui_cursor_shape(); // may show different cursor shape
}
/*
* ":normal[!] {commands}": Execute normal mode commands.
*/
@@ -8218,15 +8269,7 @@ static void ex_normal(exarg_T *eap)
EMSG("Can't re-enter normal mode from terminal mode");
return;
}
int save_msg_scroll = msg_scroll;
int save_restart_edit = restart_edit;
int save_msg_didout = msg_didout;
int save_State = State;
tasave_T tabuf;
int save_insertmode = p_im;
int save_finish_op = finish_op;
long save_opcount = opcount;
const int save_reg_executing = reg_executing;
save_state_T save_state;
char_u *arg = NULL;
int l;
char_u *p;
@@ -8239,11 +8282,6 @@ static void ex_normal(exarg_T *eap)
EMSG(_("E192: Recursive use of :normal too deep"));
return;
}
++ex_normal_busy;
msg_scroll = FALSE; /* no msg scrolling in Normal mode */
restart_edit = 0; /* don't go to Insert mode */
p_im = FALSE; /* don't use 'insertmode' */
/*
* vgetc() expects a CSI and K_SPECIAL to have been escaped. Don't do
@@ -8277,19 +8315,11 @@ static void ex_normal(exarg_T *eap)
}
}
/*
* Save the current typeahead. This is required to allow using ":normal"
* from an event handler and makes sure we don't hang when the argument
* ends with half a command.
*/
save_typeahead(&tabuf);
// TODO(philix): after save_typeahead() this is always TRUE
if (tabuf.typebuf_valid) {
/*
* Repeat the :normal command for each line in the range. When no
* range given, execute it just once, without positioning the cursor
* first.
*/
ex_normal_busy++;
if (save_current_state(&save_state)) {
// Repeat the :normal command for each line in the range. When no
// range given, execute it just once, without positioning the cursor
// first.
do {
if (eap->addr_count != 0) {
curwin->w_cursor.lnum = eap->line1++;
@@ -8306,29 +8336,12 @@ static void ex_normal(exarg_T *eap)
/* Might not return to the main loop when in an event handler. */
update_topline_cursor();
/* Restore the previous typeahead. */
restore_typeahead(&tabuf);
restore_current_state(&save_state);
--ex_normal_busy;
msg_scroll = save_msg_scroll;
if (force_restart_edit) {
force_restart_edit = false;
} else {
// Some function (terminal_enter()) was aware of ex_normal and decided to
// override the value of restart_edit anyway.
restart_edit = save_restart_edit;
}
p_im = save_insertmode;
finish_op = save_finish_op;
opcount = save_opcount;
reg_executing = save_reg_executing;
msg_didout |= save_msg_didout; // don't reset msg_didout now
ex_normal_busy--;
/* Restore the state (needed when called from a function executed for
* 'indentexpr'). Update the mouse and cursor, they may have changed. */
State = save_State;
setmouse();
ui_cursor_shape(); /* may show different cursor shape */
ui_cursor_shape(); // may show different cursor shape
xfree(arg);
}

View File

@@ -20,6 +20,20 @@
#define EXMODE_NORMAL 1
#define EXMODE_VIM 2
// Structure used to save the current state. Used when executing Normal mode
// commands while in any other mode.
typedef struct {
int save_msg_scroll;
int save_restart_edit;
int save_msg_didout;
int save_State;
int save_insertmode;
bool save_finish_op;
long save_opcount;
int save_reg_executing;
tasave_T tabuf;
} save_state_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_docmd.h.generated.h"
#endif

View File

@@ -1216,7 +1216,7 @@ void save_typeahead(tasave_T *tp)
{
tp->save_typebuf = typebuf;
alloc_typebuf();
tp->typebuf_valid = TRUE;
tp->typebuf_valid = true;
tp->old_char = old_char;
tp->old_mod_mask = old_mod_mask;
old_char = -1;

View File

@@ -1410,7 +1410,7 @@ static int menu_is_hidden(char_u *name)
static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
FUNC_ATTR_NONNULL_ARG(2)
{
int idx;
int idx = -1;
char_u *mode;
// Use the Insert mode entry when returning to Insert mode.
@@ -1464,9 +1464,13 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
/* Adjust the cursor to make sure it is in the correct pos
* for exclusive mode */
if (*p_sel == 'e' && gchar_cursor() != NUL)
++curwin->w_cursor.col;
} else {
if (*p_sel == 'e' && gchar_cursor() != NUL) {
curwin->w_cursor.col++;
}
}
// For the WinBar menu always use the Normal mode menu.
if (idx == -1 || eap == NULL) {
mode = (char_u *)"Normal";
idx = MENU_INDEX_NORMAL;
}
@@ -1477,8 +1481,15 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
// Also for the window toolbar
// Otherwise put them in the typeahead buffer.
if (eap == NULL || current_sctx.sc_sid != 0) {
save_state_T save_state;
ex_normal_busy++;
if (save_current_state(&save_state)) {
exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
menu->silent[idx]);
}
restore_current_state(&save_state);
ex_normal_busy--;
} else {
ins_typebuf(menu->strings[idx], menu->noremap[idx], 0, true,
menu->silent[idx]);
@@ -1540,11 +1551,17 @@ void winbar_click(win_T *wp, int col)
if (col >= item->wb_startcol && col <= item->wb_endcol) {
win_T *save_curwin = NULL;
const pos_T save_visual = VIsual;
const int save_visual_active = VIsual_active;
const int save_visual_select = VIsual_select;
const int save_visual_reselect = VIsual_reselect;
const int save_visual_mode = VIsual_mode;
if (wp != curwin) {
// Clicking in the window toolbar of a not-current window.
// Make that window the current one and go to Normal mode.
// Make that window the current one and save Visual mode.
save_curwin = curwin;
VIsual_active = false;
curwin = wp;
curbuf = curwin->w_buffer;
check_cursor();
@@ -1555,6 +1572,11 @@ void winbar_click(win_T *wp, int col)
if (save_curwin != NULL) {
curwin = save_curwin;
curbuf = curwin->w_buffer;
VIsual = save_visual;
VIsual_active = save_visual_active;
VIsual_select = save_visual_select;
VIsual_reselect = save_visual_reselect;
VIsual_mode = save_visual_mode;
}
}
}