diff options
-rw-r--r-- | src/nvim/normal.c | 318 |
1 files changed, 168 insertions, 150 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 3b23c4e7dc..de884acdcb 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -70,6 +70,7 @@ typedef struct normal_state { VimState state; linenr_T conceal_old_cursor_line; linenr_T conceal_new_cursor_line; + bool command_finished; bool ctrl_w; bool need_flushbuf; bool conceal_update_lines; @@ -82,8 +83,11 @@ typedef struct normal_state { oparg_T oa; // operator arguments cmdarg_T ca; // command arguments int mapped_len; + int old_mapped_len; int idx; int c; + int old_col; + pos_T old_pos; } NormalState; /* @@ -800,13 +804,157 @@ static bool normal_get_command_count(NormalState *s) return false; } +static void normal_finish_command(NormalState *s) +{ + if (s->command_finished) { + goto normal_end; + } + + // If we didn't start or finish an operator, reset oap->regname, unless we + // need it later. + if (!finish_op + && !s->oa.op_type + && (s->idx < 0 || !(nv_cmds[s->idx].cmd_flags & NV_KEEPREG))) { + clearop(&s->oa); + set_reg_var(get_default_register_name()); + } + + // Get the length of mapped chars again after typing a count, second + // character or "z333<cr>". + if (s->old_mapped_len > 0) { + s->old_mapped_len = typebuf_maplen(); + } + + // If an operation is pending, handle it... + do_pending_operator(&s->ca, s->old_col, false); + + // Wait for a moment when a message is displayed that will be overwritten + // by the mode message. + // In Visual mode and with "^O" in Insert mode, a short message will be + // overwritten by the mode message. Wait a bit, until a key is hit. + // In Visual mode, it's more important to keep the Visual area updated + // than keeping a message (e.g. from a /pat search). + // Only do this if the command was typed, not from a mapping. + // Don't wait when emsg_silent is non-zero. + // Also wait a bit after an error message, e.g. for "^O:". + // Don't redraw the screen, it would remove the message. + if (((p_smd && msg_silent == 0 && (restart_edit != 0 || (VIsual_active + && s->old_pos.lnum == curwin->w_cursor.lnum + && s->old_pos.col == curwin->w_cursor.col)) + && (clear_cmdline || redraw_cmdline) + && (msg_didout || (msg_didany && msg_scroll)) + && !msg_nowait + && KeyTyped) || (restart_edit != 0 && !VIsual_active && (msg_scroll + || emsg_on_display))) + && s->oa.regname == 0 + && !(s->ca.retval & CA_COMMAND_BUSY) + && stuff_empty() + && typebuf_typed() + && emsg_silent == 0 + && !did_wait_return + && s->oa.op_type == OP_NOP) { + int save_State = State; + + // Draw the cursor with the right shape here + if (restart_edit != 0) { + State = INSERT; + } + + // If need to redraw, and there is a "keep_msg", redraw before the + // delay + if (must_redraw && keep_msg != NULL && !emsg_on_display) { + char_u *kmsg; + + kmsg = keep_msg; + keep_msg = NULL; + // showmode() will clear keep_msg, but we want to use it anyway + update_screen(0); + // now reset it, otherwise it's put in the history again + keep_msg = kmsg; + msg_attr(kmsg, keep_msg_attr); + xfree(kmsg); + } + setcursor(); + ui_flush(); + if (msg_scroll || emsg_on_display) { + os_delay(1000L, true); // wait at least one second + } + os_delay(3000L, false); // wait up to three seconds + State = save_State; + + msg_scroll = false; + emsg_on_display = false; + } + + // Finish up after executing a Normal mode command. +normal_end: + + msg_nowait = false; + + // Reset finish_op, in case it was set + s->c = finish_op; + finish_op = false; + // Redraw the cursor with another shape, if we were in Operator-pending + // mode or did a replace command. + if (s->c || s->ca.cmdchar == 'r') { + ui_cursor_shape(); // may show different cursor shape + } + + if (s->oa.op_type == OP_NOP && s->oa.regname == 0 + && s->ca.cmdchar != K_EVENT) { + clear_showcmd(); + } + + checkpcmark(); // check if we moved since setting pcmark + xfree(s->ca.searchbuf); + + if (has_mbyte) { + mb_adjust_cursor(); + } + + if (curwin->w_p_scb && s->toplevel) { + validate_cursor(); // may need to update w_leftcol + do_check_scrollbind(true); + } + + if (curwin->w_p_crb && s->toplevel) { + validate_cursor(); // may need to update w_leftcol + do_check_cursorbind(); + } + + // May restart edit(), if we got here with CTRL-O in Insert mode (but not + // if still inside a mapping that started in Visual mode). + // May switch from Visual to Select mode after CTRL-O command. + if (s->oa.op_type == OP_NOP + && ((restart_edit != 0 && !VIsual_active && s->old_mapped_len == 0) + || restart_VIsual_select == 1) + && !(s->ca.retval & CA_COMMAND_BUSY) + && stuff_empty() + && s->oa.regname == 0) { + if (restart_VIsual_select == 1) { + VIsual_select = true; + showmode(); + restart_VIsual_select = 0; + } + if (restart_edit != 0 && !VIsual_active && s->old_mapped_len == 0) { + (void)edit(restart_edit, false, 1L); + } + } + + if (restart_VIsual_select == 2) { + restart_VIsual_select = 1; + } + + // Save count before an operator for next time + opcount = s->ca.opcount; +} + static int normal_execute(VimState *state, int key) { NormalState *s = (NormalState *)state; + s->command_finished = false; s->ctrl_w = false; /* got CTRL-W command */ - int old_col = curwin->w_curswant; - pos_T old_pos; /* cursor position before command */ - static int old_mapped_len = 0; + s->old_col = curwin->w_curswant; s->c = key; LANGMAP_ADJUST(s->c, true); @@ -815,10 +963,10 @@ static int normal_execute(VimState *state, int key) // of the mapping. This is used below to not return to Insert mode for as // long as the mapping is being executed. if (restart_edit == 0) { - old_mapped_len = 0; - } else if (old_mapped_len || (VIsual_active && s->mapped_len == 0 + s->old_mapped_len = 0; + } else if (s->old_mapped_len || (VIsual_active && s->mapped_len == 0 && typebuf_maplen() > 0)) { - old_mapped_len = typebuf_maplen(); + s->old_mapped_len = typebuf_maplen(); } if (s->c == NUL) { @@ -840,7 +988,7 @@ static int normal_execute(VimState *state, int key) s->c = 'c'; } msg_nowait = true; // don't delay going to insert mode - old_mapped_len = 0; // do go to Insert mode + s->old_mapped_len = 0; // do go to Insert mode } s->need_flushbuf = add_to_showcmd(s->c); @@ -894,23 +1042,27 @@ static int normal_execute(VimState *state, int key) if (s->idx < 0) { // Not a known command: beep. clearopbeep(&s->oa); - goto normal_end; + s->command_finished = true; + goto finish; } if (text_locked() && (nv_cmds[s->idx].cmd_flags & NV_NCW)) { // This command is not allowed while editing a cmdline: beep. clearopbeep(&s->oa); text_locked_msg(); - goto normal_end; + s->command_finished = true; + goto finish; } if ((nv_cmds[s->idx].cmd_flags & NV_NCW) && curbuf_locked()) { - goto normal_end; + s->command_finished = true; + goto finish; } // In Visual/Select mode, a few keys are handled in a special way. if (VIsual_active && normal_handle_special_visual_command(s)) { - goto normal_end; + s->command_finished = true; + goto finish; } if (curwin->w_p_rl && KeyTyped && !KeyStuffed @@ -944,7 +1096,8 @@ static int normal_execute(VimState *state, int key) if (restart_edit == 0 && goto_im()) { restart_edit = 'a'; } - goto normal_end; + s->command_finished = true; + goto finish; } if (s->ca.cmdchar != K_IGNORE) { @@ -952,7 +1105,7 @@ static int normal_execute(VimState *state, int key) msg_col = 0; } - old_pos = curwin->w_cursor; // remember where cursor was + s->old_pos = curwin->w_cursor; // remember where cursor was // When 'keymodel' contains "startsel" some keys start Select/Visual // mode. @@ -973,143 +1126,8 @@ static int normal_execute(VimState *state, int key) s->ca.arg = nv_cmds[s->idx].cmd_arg; (nv_cmds[s->idx].cmd_func)(&s->ca); - // If we didn't start or finish an operator, reset oap->regname, unless we - // need it later. - if (!finish_op - && !s->oa.op_type - && (s->idx < 0 || !(nv_cmds[s->idx].cmd_flags & NV_KEEPREG))) { - clearop(&s->oa); - set_reg_var(get_default_register_name()); - } - - // Get the length of mapped chars again after typing a count, second - // character or "z333<cr>". - if (old_mapped_len > 0) { - old_mapped_len = typebuf_maplen(); - } - - // If an operation is pending, handle it... - do_pending_operator(&s->ca, old_col, false); - - // Wait for a moment when a message is displayed that will be overwritten - // by the mode message. - // In Visual mode and with "^O" in Insert mode, a short message will be - // overwritten by the mode message. Wait a bit, until a key is hit. - // In Visual mode, it's more important to keep the Visual area updated - // than keeping a message (e.g. from a /pat search). - // Only do this if the command was typed, not from a mapping. - // Don't wait when emsg_silent is non-zero. - // Also wait a bit after an error message, e.g. for "^O:". - // Don't redraw the screen, it would remove the message. - if (((p_smd && msg_silent == 0 && (restart_edit != 0 || (VIsual_active - && old_pos.lnum == curwin->w_cursor.lnum - && old_pos.col == curwin->w_cursor.col)) - && (clear_cmdline || redraw_cmdline) - && (msg_didout || (msg_didany && msg_scroll)) - && !msg_nowait - && KeyTyped) || (restart_edit != 0 && !VIsual_active && (msg_scroll - || emsg_on_display))) - && s->oa.regname == 0 - && !(s->ca.retval & CA_COMMAND_BUSY) - && stuff_empty() - && typebuf_typed() - && emsg_silent == 0 - && !did_wait_return - && s->oa.op_type == OP_NOP) { - int save_State = State; - - // Draw the cursor with the right shape here - if (restart_edit != 0) { - State = INSERT; - } - - // If need to redraw, and there is a "keep_msg", redraw before the - // delay - if (must_redraw && keep_msg != NULL && !emsg_on_display) { - char_u *kmsg; - - kmsg = keep_msg; - keep_msg = NULL; - // showmode() will clear keep_msg, but we want to use it anyway - update_screen(0); - // now reset it, otherwise it's put in the history again - keep_msg = kmsg; - msg_attr(kmsg, keep_msg_attr); - xfree(kmsg); - } - setcursor(); - ui_flush(); - if (msg_scroll || emsg_on_display) { - os_delay(1000L, true); // wait at least one second - } - os_delay(3000L, false); // wait up to three seconds - State = save_State; - - msg_scroll = false; - emsg_on_display = false; - } - - // Finish up after executing a Normal mode command. -normal_end: - - msg_nowait = false; - - // Reset finish_op, in case it was set - s->c = finish_op; - finish_op = false; - // Redraw the cursor with another shape, if we were in Operator-pending - // mode or did a replace command. - if (s->c || s->ca.cmdchar == 'r') { - ui_cursor_shape(); // may show different cursor shape - } - - if (s->oa.op_type == OP_NOP && s->oa.regname == 0 - && s->ca.cmdchar != K_EVENT) { - clear_showcmd(); - } - - checkpcmark(); // check if we moved since setting pcmark - xfree(s->ca.searchbuf); - - if (has_mbyte) { - mb_adjust_cursor(); - } - - if (curwin->w_p_scb && s->toplevel) { - validate_cursor(); // may need to update w_leftcol - do_check_scrollbind(true); - } - - if (curwin->w_p_crb && s->toplevel) { - validate_cursor(); // may need to update w_leftcol - do_check_cursorbind(); - } - - // May restart edit(), if we got here with CTRL-O in Insert mode (but not - // if still inside a mapping that started in Visual mode). - // May switch from Visual to Select mode after CTRL-O command. - if (s->oa.op_type == OP_NOP - && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0) - || restart_VIsual_select == 1) - && !(s->ca.retval & CA_COMMAND_BUSY) - && stuff_empty() - && s->oa.regname == 0) { - if (restart_VIsual_select == 1) { - VIsual_select = true; - showmode(); - restart_VIsual_select = 0; - } - if (restart_edit != 0 && !VIsual_active && old_mapped_len == 0) { - (void)edit(restart_edit, false, 1L); - } - } - - if (restart_VIsual_select == 2) { - restart_VIsual_select = 1; - } - - // Save count before an operator for next time - opcount = s->ca.opcount; +finish: + normal_finish_command(s); return 1; } |