diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/buffer_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 107 | ||||
-rw-r--r-- | src/nvim/ex_docmd.h | 14 | ||||
-rw-r--r-- | src/nvim/getchar.c | 2 | ||||
-rw-r--r-- | src/nvim/menu.c | 36 |
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; } } } |