aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/ex_docmd.c107
-rw-r--r--src/nvim/ex_docmd.h14
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/menu.c36
5 files changed, 105 insertions, 56 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 667c1854ab..61cc9e536b 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -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;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 27d5e4998f..373bd93b24 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -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);
}
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index cff350de08..f6bd2adcd5 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -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
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 0debd39555..5ab5a7db1b 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -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;
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index b43a24d0a9..9d37035247 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -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) {
- exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
- menu->silent[idx]);
+ 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;
}
}
}