From dae006a942213f1c37ecfd20ac79d2f7fc462696 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sun, 4 Oct 2015 09:36:34 -0300 Subject: main: Extract `normal_check` from `main_loop` The new function contains logic that must be executed after handling input in normal mode and also before the first main loop iteration. Also rename `main_loop` to `normal_enter` and move it to normal.c --- src/nvim/ex_docmd.c | 2 +- src/nvim/ex_getln.c | 2 +- src/nvim/main.c | 218 +-------------------------------------------- src/nvim/normal.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 216 deletions(-) (limited to 'src') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a9262ca6ea..e160281145 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6544,7 +6544,7 @@ do_exedit ( msg_scroll = 0; must_redraw = CLEAR; - main_loop(FALSE, TRUE); + normal_enter(false, true); RedrawingDisabled = rd; no_wait_return = nwr; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 50e9ce7c17..7b9fd1e61e 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4943,7 +4943,7 @@ static int ex_window(void) * Call the main loop until or CTRL-C is typed. */ cmdwin_result = 0; - main_loop(TRUE, FALSE); + normal_enter(true, false); RedrawingDisabled = i; diff --git a/src/nvim/main.c b/src/nvim/main.c index 60a242fae3..06fd116b86 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -528,228 +528,16 @@ int main(int argc, char **argv) } TIME_MSG("before starting main loop"); + ILOG("Starting Neovim main loop."); /* * Call the main command loop. This never returns. */ - main_loop(FALSE, FALSE); + normal_enter(false, false); return 0; } -/* - * Main loop: Execute Normal mode commands until exiting Vim. - * Also used to handle commands in the command-line window, until the window - * is closed. - * Also used to handle ":visual" command after ":global": execute Normal mode - * commands, return when entering Ex mode. "noexmode" is TRUE then. - */ -void -main_loop ( - int cmdwin, /* TRUE when working in the command-line window */ - int noexmode /* TRUE when return on entering Ex mode */ -) -{ - oparg_T oa; /* operator arguments */ - int previous_got_int = FALSE; /* "got_int" was TRUE */ - linenr_T conceal_old_cursor_line = 0; - linenr_T conceal_new_cursor_line = 0; - int conceal_update_lines = FALSE; - - ILOG("Starting Neovim main loop."); - - clear_oparg(&oa); - while (!cmdwin - || cmdwin_result == 0 - ) { - if (stuff_empty()) { - did_check_timestamps = FALSE; - if (need_check_timestamps) - check_timestamps(FALSE); - if (need_wait_return) /* if wait_return still needed ... */ - wait_return(FALSE); /* ... call it now */ - if (need_start_insertmode && goto_im() - && !VIsual_active - ) { - need_start_insertmode = FALSE; - stuffReadbuff((char_u *)"i"); /* start insert mode next */ - /* skip the fileinfo message now, because it would be shown - * after insert mode finishes! */ - need_fileinfo = FALSE; - } - } - - /* Reset "got_int" now that we got back to the main loop. Except when - * inside a ":g/pat/cmd" command, then the "got_int" needs to abort - * the ":g" command. - * For ":g/pat/vi" we reset "got_int" when used once. When used - * a second time we go back to Ex mode and abort the ":g" command. */ - if (got_int) { - if (noexmode && global_busy && !exmode_active && previous_got_int) { - /* Typed two CTRL-C in a row: go back to ex mode as if "Q" was - * used and keep "got_int" set, so that it aborts ":g". */ - exmode_active = EXMODE_NORMAL; - State = NORMAL; - } else if (!global_busy || !exmode_active) { - if (!quit_more) - (void)vgetc(); /* flush all buffers */ - got_int = FALSE; - } - previous_got_int = TRUE; - } else - previous_got_int = FALSE; - - if (!exmode_active) - msg_scroll = FALSE; - quit_more = FALSE; - - /* - * If skip redraw is set (for ":" in wait_return()), don't redraw now. - * If there is nothing in the stuff_buffer or do_redraw is TRUE, - * update cursor and redraw. - */ - if (skip_redraw || exmode_active) - skip_redraw = FALSE; - else if (do_redraw || stuff_empty()) { - /* Trigger CursorMoved if the cursor moved. */ - if (!finish_op && ( - has_cursormoved() - || - curwin->w_p_cole > 0 - ) - && !equalpos(last_cursormoved, curwin->w_cursor)) { - if (has_cursormoved()) - apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, - FALSE, curbuf); - if (curwin->w_p_cole > 0) { - conceal_old_cursor_line = last_cursormoved.lnum; - conceal_new_cursor_line = curwin->w_cursor.lnum; - conceal_update_lines = TRUE; - } - last_cursormoved = curwin->w_cursor; - } - - /* Trigger TextChanged if b_changedtick differs. */ - if (!finish_op && has_textchanged() - && last_changedtick != curbuf->b_changedtick) { - if (last_changedtick_buf == curbuf) - apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, - FALSE, curbuf); - last_changedtick_buf = curbuf; - last_changedtick = curbuf->b_changedtick; - } - - /* Scroll-binding for diff mode may have been postponed until - * here. Avoids doing it for every change. */ - if (diff_need_scrollbind) { - check_scrollbind((linenr_T)0, 0L); - diff_need_scrollbind = FALSE; - } - /* Include a closed fold completely in the Visual area. */ - foldAdjustVisual(); - /* - * When 'foldclose' is set, apply 'foldlevel' to folds that don't - * contain the cursor. - * When 'foldopen' is "all", open the fold(s) under the cursor. - * This may mark the window for redrawing. - */ - if (hasAnyFolding(curwin) && !char_avail()) { - foldCheckClose(); - if (fdo_flags & FDO_ALL) - foldOpenCursor(); - } - - /* - * Before redrawing, make sure w_topline is correct, and w_leftcol - * if lines don't wrap, and w_skipcol if lines wrap. - */ - update_topline(); - validate_cursor(); - - if (VIsual_active) - update_curbuf(INVERTED); /* update inverted part */ - else if (must_redraw) - update_screen(0); - else if (redraw_cmdline || clear_cmdline) - showmode(); - redraw_statuslines(); - if (need_maketitle) - maketitle(); - /* display message after redraw */ - if (keep_msg != NULL) { - char_u *p; - - // msg_attr_keep() will set keep_msg to NULL, must free the string - // here. Don't reset keep_msg, msg_attr_keep() uses it to check for - // duplicates. - p = keep_msg; - msg_attr(p, keep_msg_attr); - xfree(p); - } - if (need_fileinfo) { /* show file info after redraw */ - fileinfo(FALSE, TRUE, FALSE); - need_fileinfo = FALSE; - } - - emsg_on_display = FALSE; /* can delete error message now */ - did_emsg = FALSE; - msg_didany = FALSE; /* reset lines_left in msg_start() */ - may_clear_sb_text(); /* clear scroll-back text on next msg */ - showruler(FALSE); - - if (conceal_update_lines - && (conceal_old_cursor_line != conceal_new_cursor_line - || conceal_cursor_line(curwin) - || need_cursor_line_redraw)) { - if (conceal_old_cursor_line != conceal_new_cursor_line - && conceal_old_cursor_line - <= curbuf->b_ml.ml_line_count) - update_single_line(curwin, conceal_old_cursor_line); - update_single_line(curwin, conceal_new_cursor_line); - curwin->w_valid &= ~VALID_CROW; - } - setcursor(); - - do_redraw = FALSE; - - /* Now that we have drawn the first screen all the startup stuff - * has been done, close any file for startup messages. */ - if (time_fd != NULL) { - TIME_MSG("first screen update"); - TIME_MSG("--- NVIM STARTED ---"); - fclose(time_fd); - time_fd = NULL; - } - } - - /* - * Update w_curswant if w_set_curswant has been set. - * Postponed until here to avoid computing w_virtcol too often. - */ - update_curswant(); - - /* - * May perform garbage collection when waiting for a character, but - * only at the very toplevel. Otherwise we may be using a List or - * Dict internally somewhere. - * "may_garbage_collect" is reset in vgetc() which is invoked through - * do_exmode() and normal_cmd(). - */ - may_garbage_collect = (!cmdwin && !noexmode); - /* - * If we're invoked as ex, do a round of ex commands. - * Otherwise, get and execute a normal mode command. - */ - if (exmode_active) { - if (noexmode) /* End of ":global/path/visual" commands */ - return; - do_exmode(exmode_active == EXMODE_VIM); - } else - normal_cmd(&oa, TRUE); - } -} - - /* Exit properly */ void getout(int exitval) { @@ -2075,3 +1863,5 @@ static void check_swap_exists_action(void) getout(1); handle_swap_exists(NULL); } + + diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 713aa55500..fe1eb5b4a0 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -65,6 +65,19 @@ #include "nvim/os/time.h" #include "nvim/os/input.h" +typedef struct normal_state { + linenr_T conceal_old_cursor_line; + linenr_T conceal_new_cursor_line; + bool conceal_update_lines; + bool previous_got_int; // `got_int` was true + bool cmdwin; // command-line window normal mode + bool noexmode; // true if the normal mode was pushed from + // ex mode(:global or :visual for example) + bool toplevel; // top-level normal mode + oparg_T oa; // operator arguments + cmdarg_T ca; // command arguments +} NormalState; + /* * The Visual area is remembered for reselection. */ @@ -79,6 +92,12 @@ static int restart_VIsual_select = 0; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "normal.c.generated.h" #endif + +static inline void normal_state_init(NormalState *s) +{ + memset(s, 0, sizeof(NormalState)); +} + /* * nv_*(): functions called to handle Normal and Visual mode commands. * n_*(): functions called to handle Normal mode commands. @@ -418,6 +437,34 @@ static int find_command(int cmdchar) return idx; } +// Normal state entry point. This is called on: +// +// - Startup, In this case the function never returns. +// - The command-line window is opened(`q:`). Returns when `cmdwin_result` != 0. +// - The :visual command is called from :global in ex mode, `:global/PAT/visual` +// for example. Returns when re-entering ex mode(because ex mode recursion is +// not allowed) +// +// This used to be called main_loop on main.c +void normal_enter(bool cmdwin, bool noexmode) +{ + NormalState state; + normal_state_init(&state); + state.cmdwin = cmdwin; + state.noexmode = noexmode; + state.toplevel = !cmdwin && !noexmode; + + for (;;) { + int check_result = normal_check(&state); + if (!check_result) { + break; + } else if (check_result == -1) { + continue; + } + normal_cmd(&state.oa, true); + } +} + /* * Execute a command in Normal mode. */ @@ -1064,6 +1111,209 @@ normal_end: opcount = ca.opcount; } +// Function executed before each iteration of normal mode. +// Return: +// 1 if the iteration should continue normally +// -1 if the iteration should be skipped +// 0 if the main loop must exit +static int normal_check(NormalState *s) +{ + if (stuff_empty()) { + did_check_timestamps = false; + + if (need_check_timestamps) { + check_timestamps(false); + } + + if (need_wait_return) { + // if wait_return still needed call it now + wait_return(false); + } + + if (need_start_insertmode && goto_im() && !VIsual_active) { + need_start_insertmode = false; + stuffReadbuff((uint8_t *)"i"); // start insert mode next + // skip the fileinfo message now, because it would be shown + // after insert mode finishes! + need_fileinfo = false; + } + } + + // Reset "got_int" now that we got back to the main loop. Except when + // inside a ":g/pat/cmd" command, then the "got_int" needs to abort + // the ":g" command. + // For ":g/pat/vi" we reset "got_int" when used once. When used + // a second time we go back to Ex mode and abort the ":g" command. + if (got_int) { + if (s->noexmode && global_busy && !exmode_active + && s->previous_got_int) { + // Typed two CTRL-C in a row: go back to ex mode as if "Q" was + // used and keep "got_int" set, so that it aborts ":g". + exmode_active = EXMODE_NORMAL; + State = NORMAL; + } else if (!global_busy || !exmode_active) { + if (!quit_more) { + // flush all buffers + (void)vgetc(); + } + got_int = false; + } + s->previous_got_int = true; + } else { + s->previous_got_int = false; + } + + if (!exmode_active) { + msg_scroll = false; + } + quit_more = false; + + // If skip redraw is set (for ":" in wait_return()), don't redraw now. + // If there is nothing in the stuff_buffer or do_redraw is TRUE, + // update cursor and redraw. + if (skip_redraw || exmode_active) { + skip_redraw = false; + } else if (do_redraw || stuff_empty()) { + // Trigger CursorMoved if the cursor moved. + if (!finish_op && (has_cursormoved() || curwin->w_p_cole > 0) + && !equalpos(last_cursormoved, curwin->w_cursor)) { + if (has_cursormoved()) { + apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, false, curbuf); + } + + if (curwin->w_p_cole > 0) { + s->conceal_old_cursor_line = last_cursormoved.lnum; + s->conceal_new_cursor_line = curwin->w_cursor.lnum; + s->conceal_update_lines = true; + } + + last_cursormoved = curwin->w_cursor; + } + + // Trigger TextChanged if b_changedtick differs. + if (!finish_op && has_textchanged() + && last_changedtick != curbuf->b_changedtick) { + if (last_changedtick_buf == curbuf) { + apply_autocmds(EVENT_TEXTCHANGED, NULL, NULL, false, curbuf); + } + + last_changedtick_buf = curbuf; + last_changedtick = curbuf->b_changedtick; + } + + // Scroll-binding for diff mode may have been postponed until + // here. Avoids doing it for every change. + if (diff_need_scrollbind) { + check_scrollbind((linenr_T)0, 0L); + diff_need_scrollbind = false; + } + + // Include a closed fold completely in the Visual area. + foldAdjustVisual(); + + // When 'foldclose' is set, apply 'foldlevel' to folds that don't + // contain the cursor. + // When 'foldopen' is "all", open the fold(s) under the cursor. + // This may mark the window for redrawing. + if (hasAnyFolding(curwin) && !char_avail()) { + foldCheckClose(); + + if (fdo_flags & FDO_ALL) { + foldOpenCursor(); + } + } + + // Before redrawing, make sure w_topline is correct, and w_leftcol + // if lines don't wrap, and w_skipcol if lines wrap. + update_topline(); + validate_cursor(); + + if (VIsual_active) { + update_curbuf(INVERTED); // update inverted part + } else if (must_redraw) { + update_screen(0); + } else if (redraw_cmdline || clear_cmdline) { + showmode(); + } + + redraw_statuslines(); + + if (need_maketitle) { + maketitle(); + } + + // display message after redraw + if (keep_msg != NULL) { + // msg_attr_keep() will set keep_msg to NULL, must free the string here. + // Don't reset keep_msg, msg_attr_keep() uses it to check for duplicates. + char *p = (char *)keep_msg; + msg_attr((uint8_t *)p, keep_msg_attr); + xfree(p); + } + + if (need_fileinfo) { // show file info after redraw + fileinfo(false, true, false); + need_fileinfo = false; + } + + emsg_on_display = false; // can delete error message now + did_emsg = false; + msg_didany = false; // reset lines_left in msg_start() + may_clear_sb_text(); // clear scroll-back text on next msg + showruler(false); + + if (s->conceal_update_lines + && (s->conceal_old_cursor_line != + s->conceal_new_cursor_line + || conceal_cursor_line(curwin) + || need_cursor_line_redraw)) { + if (s->conceal_old_cursor_line != + s->conceal_new_cursor_line + && s->conceal_old_cursor_line <= + curbuf->b_ml.ml_line_count) { + update_single_line(curwin, s->conceal_old_cursor_line); + } + + update_single_line(curwin, s->conceal_new_cursor_line); + curwin->w_valid &= ~VALID_CROW; + } + + setcursor(); + + do_redraw = false; + + // Now that we have drawn the first screen all the startup stuff + // has been done, close any file for startup messages. + if (time_fd != NULL) { + TIME_MSG("first screen update"); + TIME_MSG("--- NVIM STARTED ---"); + fclose(time_fd); + time_fd = NULL; + } + } + + // May perform garbage collection when waiting for a character, but + // only at the very toplevel. Otherwise we may be using a List or + // Dict internally somewhere. + // "may_garbage_collect" is reset in vgetc() which is invoked through + // do_exmode() and normal_cmd(). + may_garbage_collect = s->toplevel; + + // Update w_curswant if w_set_curswant has been set. + // Postponed until here to avoid computing w_virtcol too often. + update_curswant(); + + if (exmode_active) { + if (s->noexmode) { + return 0; + } + do_exmode(exmode_active == EXMODE_VIM); + return -1; + } + + return !s->cmdwin || cmdwin_result == 0; +} + /* * Set v:count and v:count1 according to "cap". * Set v:prevcount only when "set_prevcount" is true. @@ -7376,3 +7626,4 @@ static int mouse_model_popup(void) { return p_mousem[0] == 'p'; } + -- cgit From 82bb8c887c5625a77969c70a38ce94fce803301e Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sun, 4 Oct 2015 09:38:26 -0300 Subject: normal: Extract most `normal_cmd` logic into two functions The new functions are `normal_prepare` and `normal_execute` which contain code executed before and after input is received in normal mode. --- src/nvim/normal.c | 78 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index fe1eb5b4a0..d2d734a677 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -69,6 +69,7 @@ typedef struct normal_state { linenr_T conceal_old_cursor_line; linenr_T conceal_new_cursor_line; bool conceal_update_lines; + bool set_prevcount; bool previous_got_int; // `got_int` was true bool cmdwin; // command-line window normal mode bool noexmode; // true if the normal mode was pushed from @@ -76,6 +77,7 @@ typedef struct normal_state { bool toplevel; // top-level normal mode oparg_T oa; // operator arguments cmdarg_T ca; // command arguments + int mapped_len; } NormalState; /* @@ -465,26 +467,11 @@ void normal_enter(bool cmdwin, bool noexmode) } } -/* - * Execute a command in Normal mode. - */ -void -normal_cmd ( - oparg_T *oap, - bool toplevel /* true when called from main() */ -) +static void normal_prepare(NormalState *s) { cmdarg_T ca; /* command arguments */ int c; - bool ctrl_w = false; /* got CTRL-W command */ - int old_col = curwin->w_curswant; - bool need_flushbuf; /* need to call ui_flush() */ - pos_T old_pos; /* cursor position before command */ - int mapped_len; - static int old_mapped_len = 0; - int idx; - bool set_prevcount = false; - + oparg_T *oap = &s->oa; memset(&ca, 0, sizeof(ca)); /* also resets ca.retval */ ca.oap = oap; @@ -509,7 +496,7 @@ normal_cmd ( * count. */ if (!finish_op && !oap->regname) { ca.opcount = 0; - set_prevcount = true; + s->set_prevcount = true; } /* Restore counts from before receiving K_CURSORHOLD. This means after @@ -522,27 +509,31 @@ normal_cmd ( oap->prev_count0 = 0; } - mapped_len = typebuf_maplen(); + s->mapped_len = typebuf_maplen(); State = NORMAL_BUSY; /* Set v:count here, when called from main() and not a stuffed * command, so that v:count can be used in an expression mapping * when there is no count. Do set it for redo. */ - if (toplevel && readbuf1_empty()) - set_vcount_ca(&ca, &set_prevcount); - - /* - * Get the command character from the user. - */ - input_enable_events(); - c = safe_vgetc(); - input_disable_events(); + if (s->toplevel && readbuf1_empty()) + set_vcount_ca(&ca, &s->set_prevcount); + s->ca = ca; +} - if (c == K_EVENT) { - queue_process_events(loop.events); - return; - } +static int normal_execute(NormalState *s, int c) +{ + cmdarg_T ca = s->ca; + bool ctrl_w = false; /* got CTRL-W command */ + int old_col = curwin->w_curswant; + bool need_flushbuf; /* need to call ui_flush() */ + pos_T old_pos; /* cursor position before command */ + int mapped_len = s->mapped_len; + static int old_mapped_len = 0; + int idx; + bool set_prevcount = s->set_prevcount; + bool toplevel = s->toplevel; + oparg_T *oap = &s->oa; LANGMAP_ADJUST(c, true); @@ -1109,6 +1100,7 @@ normal_end: /* Save count before an operator for next time. */ opcount = ca.opcount; + return 1; } // Function executed before each iteration of normal mode. @@ -7627,3 +7619,25 @@ static int mouse_model_popup(void) return p_mousem[0] == 'p'; } +void normal_cmd(oparg_T *oap, bool toplevel) +{ + NormalState s; + normal_state_init(&s); + s.toplevel = toplevel; + s.oa = *oap; + normal_prepare(&s); + + input_enable_events(); + int c = safe_vgetc(); + input_disable_events(); + + if (c == K_EVENT) { + queue_process_events(loop.events); + goto end; + } + + (void)normal_execute(&s, c); + +end: + *oap = s.oa; +} -- cgit From d8055f8eab7b1c3fb90f69e9795e9e2a88d0cd68 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sun, 4 Oct 2015 10:05:54 -0300 Subject: normal: Fix code style in `normal_prepare` and `normal_execute` This was done separately to make it easier to follow the changes in the previous commit. --- src/nvim/normal.c | 696 ++++++++++++++++++++++++++---------------------------- 1 file changed, 332 insertions(+), 364 deletions(-) (limited to 'src') diff --git a/src/nvim/normal.c b/src/nvim/normal.c index d2d734a677..11ef093ee7 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -469,137 +469,127 @@ void normal_enter(bool cmdwin, bool noexmode) static void normal_prepare(NormalState *s) { - cmdarg_T ca; /* command arguments */ - int c; - oparg_T *oap = &s->oa; - memset(&ca, 0, sizeof(ca)); /* also resets ca.retval */ - ca.oap = oap; - - /* Use a count remembered from before entering an operator. After typing - * "3d" we return from normal_cmd() and come back here, the "3" is - * remembered in "opcount". */ - ca.opcount = opcount; - - - /* - * If there is an operator pending, then the command we take this time - * will terminate it. Finish_op tells us to finish the operation before - * returning this time (unless the operation was cancelled). - */ - c = finish_op; - finish_op = (oap->op_type != OP_NOP); + memset(&s->ca, 0, sizeof(s->ca)); // also resets ca.retval + s->ca.oap = &s->oa; + + // Use a count remembered from before entering an operator. After typing "3d" + // we return from normal_cmd() and come back here, the "3" is remembered in + // "opcount". + s->ca.opcount = opcount; + + // If there is an operator pending, then the command we take this time will + // terminate it. Finish_op tells us to finish the operation before returning + // this time (unless the operation was cancelled). + int c = finish_op; + finish_op = (s->oa.op_type != OP_NOP); if (finish_op != c) { - ui_cursor_shape(); /* may show different cursor shape */ + ui_cursor_shape(); // may show different cursor shape } - /* When not finishing an operator and no register name typed, reset the - * count. */ - if (!finish_op && !oap->regname) { - ca.opcount = 0; + // When not finishing an operator and no register name typed, reset the count. + if (!finish_op && !s->oa.regname) { + s->ca.opcount = 0; s->set_prevcount = true; } - /* Restore counts from before receiving K_CURSORHOLD. This means after - * typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not - * "3 * 2". */ - if (oap->prev_opcount > 0 || oap->prev_count0 > 0) { - ca.opcount = oap->prev_opcount; - ca.count0 = oap->prev_count0; - oap->prev_opcount = 0; - oap->prev_count0 = 0; + // Restore counts from before receiving K_CURSORHOLD. This means after + // typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not + // "3 * 2". + if (s->oa.prev_opcount > 0 || s->oa.prev_count0 > 0) { + s->ca.opcount = s->oa.prev_opcount; + s->ca.count0 = s->oa.prev_count0; + s->oa.prev_opcount = 0; + s->oa.prev_count0 = 0; } s->mapped_len = typebuf_maplen(); - State = NORMAL_BUSY; - /* Set v:count here, when called from main() and not a stuffed - * command, so that v:count can be used in an expression mapping - * when there is no count. Do set it for redo. */ - if (s->toplevel && readbuf1_empty()) - set_vcount_ca(&ca, &s->set_prevcount); - s->ca = ca; + // Set v:count here, when called from main() and not a stuffed command, so + // that v:count can be used in an expression mapping when there is no count. + // Do set it for redo + if (s->toplevel && readbuf1_empty()) { + set_vcount_ca(&s->ca, &s->set_prevcount); + } } static int normal_execute(NormalState *s, int c) { - cmdarg_T ca = s->ca; bool ctrl_w = false; /* got CTRL-W command */ int old_col = curwin->w_curswant; bool need_flushbuf; /* need to call ui_flush() */ pos_T old_pos; /* cursor position before command */ - int mapped_len = s->mapped_len; static int old_mapped_len = 0; int idx; - bool set_prevcount = s->set_prevcount; - bool toplevel = s->toplevel; - oparg_T *oap = &s->oa; LANGMAP_ADJUST(c, true); - /* - * If a mapping was started in Visual or Select mode, remember the length - * 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) + // If a mapping was started in Visual or Select mode, remember the length + // 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 && mapped_len == 0 && typebuf_maplen() > 0)) + } else if (old_mapped_len || (VIsual_active && s->mapped_len == 0 + && typebuf_maplen() > 0)) { old_mapped_len = typebuf_maplen(); + } - if (c == NUL) + if (c == NUL) { c = K_ZERO; + } - /* - * In Select mode, typed text replaces the selection. - */ - if (VIsual_active - && VIsual_select + // In Select mode, typed text replaces the selection. + if (VIsual_active && VIsual_select && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER)) { - /* Fake a "c"hange command. When "restart_edit" is set (e.g., because - * 'insertmode' is set) fake a "d"elete command, Insert mode will - * restart automatically. - * Insert the typed character in the typeahead buffer, so that it can - * be mapped in Insert mode. Required for ":lmap" to work. */ + // Fake a "c"hange command. When "restart_edit" is set (e.g., because + // 'insertmode' is set) fake a "d"elete command, Insert mode will + // restart automatically. + // Insert the typed character in the typeahead buffer, so that it can + // be mapped in Insert mode. Required for ":lmap" to work. ins_char_typebuf(c); - if (restart_edit != 0) + if (restart_edit != 0) { c = 'd'; - else + } else { c = 'c'; - msg_nowait = true; /* don't delay going to insert mode */ - old_mapped_len = 0; /* do go to Insert mode */ + } + msg_nowait = true; // don't delay going to insert mode + old_mapped_len = 0; // do go to Insert mode } need_flushbuf = add_to_showcmd(c); getcount: if (!(VIsual_active && VIsual_select)) { - /* - * Handle a count before a command and compute ca.count0. - * Note that '0' is a command and not the start of a count, but it's - * part of a count after other digits. - */ - while ( (c >= '1' && c <= '9') - || (ca.count0 != 0 && - (c == K_DEL || c == K_KDEL || c == '0'))) { + // Handle a count before a command and compute ca.count0. + // Note that '0' is a command and not the start of a count, but it's + // part of a count after other digits. + while ((c >= '1' && c <= '9') || (s->ca.count0 != 0 + && (c == K_DEL || c == K_KDEL || c == '0'))) { if (c == K_DEL || c == K_KDEL) { - ca.count0 /= 10; - del_from_showcmd(4); /* delete the digit and ~@% */ - } else - ca.count0 = ca.count0 * 10 + (c - '0'); - if (ca.count0 < 0) /* got too large! */ - ca.count0 = 999999999L; - /* Set v:count here, when called from main() and not a stuffed - * command, so that v:count can be used in an expression mapping - * right after the count. Do set it for redo. */ - if (toplevel && readbuf1_empty()) - set_vcount_ca(&ca, &set_prevcount); + s->ca.count0 /= 10; + del_from_showcmd(4); // delete the digit and ~@% + } else { + s->ca.count0 = s->ca.count0 * 10 + (c - '0'); + } + + if (s->ca.count0 < 0) { + // got too large! + s->ca.count0 = 999999999L; + } + + // Set v:count here, when called from main() and not a stuffed + // command, so that v:count can be used in an expression mapping + // right after the count. Do set it for redo. + if (s->toplevel && readbuf1_empty()) { + set_vcount_ca(&s->ca, &s->set_prevcount); + } + if (ctrl_w) { ++no_mapping; - ++allow_keys; /* no mapping for nchar, but keys */ + ++allow_keys; // no mapping for nchar, but keys } - ++no_zero_mapping; /* don't map zero here */ + + ++no_zero_mapping; // don't map zero here c = plain_vgetc(); LANGMAP_ADJUST(c, true); --no_zero_mapping; @@ -610,91 +600,86 @@ getcount: need_flushbuf |= add_to_showcmd(c); } - /* - * If we got CTRL-W there may be a/another count - */ - if (c == Ctrl_W && !ctrl_w && oap->op_type == OP_NOP) { + // If we got CTRL-W there may be a/another count + if (c == Ctrl_W && !ctrl_w && s->oa.op_type == OP_NOP) { ctrl_w = true; - ca.opcount = ca.count0; /* remember first count */ - ca.count0 = 0; + s->ca.opcount = s->ca.count0; // remember first count + s->ca.count0 = 0; ++no_mapping; - ++allow_keys; /* no mapping for nchar, but keys */ - c = plain_vgetc(); /* get next character */ + ++allow_keys; // no mapping for nchar, but keys + c = plain_vgetc(); // get next character LANGMAP_ADJUST(c, true); --no_mapping; --allow_keys; need_flushbuf |= add_to_showcmd(c); - goto getcount; /* jump back */ + goto getcount; // jump back } } if (c == K_CURSORHOLD) { - /* Save the count values so that ca.opcount and ca.count0 are exactly - * the same when coming back here after handling K_CURSORHOLD. */ - oap->prev_opcount = ca.opcount; - oap->prev_count0 = ca.count0; - } else if (ca.opcount != 0) { - /* - * If we're in the middle of an operator (including after entering a - * yank buffer with '"') AND we had a count before the operator, then - * that count overrides the current value of ca.count0. - * What this means effectively, is that commands like "3dw" get turned - * into "d3w" which makes things fall into place pretty neatly. - * If you give a count before AND after the operator, they are - * multiplied. - */ - if (ca.count0) - ca.count0 *= ca.opcount; - else - ca.count0 = ca.opcount; + // Save the count values so that ca.opcount and ca.count0 are exactly + // the same when coming back here after handling K_CURSORHOLD. + s->oa.prev_opcount = s->ca.opcount; + s->oa.prev_count0 = s->ca.count0; + } else if (s->ca.opcount != 0) { + // If we're in the middle of an operator (including after entering a + // yank buffer with '"') AND we had a count before the operator, then + // that count overrides the current value of ca.count0. + // What this means effectively, is that commands like "3dw" get turned + // into "d3w" which makes things fall into place pretty neatly. + // If you give a count before AND after the operator, they are + // multiplied. + if (s->ca.count0) { + s->ca.count0 *= s->ca.opcount; + } else { + s->ca.count0 = s->ca.opcount; + } } - /* - * Always remember the count. It will be set to zero (on the next call, - * above) when there is no pending operator. - * When called from main(), save the count for use by the "count" built-in - * variable. - */ - ca.opcount = ca.count0; - ca.count1 = (ca.count0 == 0 ? 1 : ca.count0); + // Always remember the count. It will be set to zero (on the next call, + // above) when there is no pending operator. + // When called from main(), save the count for use by the "count" built-in + // variable. + s->ca.opcount = s->ca.count0; + s->ca.count1 = (s->ca.count0 == 0 ? 1 : s->ca.count0); - /* - * Only set v:count when called from main() and not a stuffed command. - * Do set it for redo. - */ - if (toplevel && readbuf1_empty()) - set_vcount(ca.count0, ca.count1, set_prevcount); + // Only set v:count when called from main() and not a stuffed command. + // Do set it for redo. + if (s->toplevel && readbuf1_empty()) { + set_vcount(s->ca.count0, s->ca.count1, s->set_prevcount); + } - /* - * Find the command character in the table of commands. - * For CTRL-W we already got nchar when looking for a count. - */ + // Find the command character in the table of commands. + // For CTRL-W we already got nchar when looking for a count. if (ctrl_w) { - ca.nchar = c; - ca.cmdchar = Ctrl_W; - } else - ca.cmdchar = c; - idx = find_command(ca.cmdchar); + s->ca.nchar = c; + s->ca.cmdchar = Ctrl_W; + } else { + s->ca.cmdchar = c; + } + + idx = find_command(s->ca.cmdchar); + if (idx < 0) { - /* Not a known command: beep. */ - clearopbeep(oap); + // Not a known command: beep. + clearopbeep(&s->oa); goto normal_end; } if (text_locked() && (nv_cmds[idx].cmd_flags & NV_NCW)) { // This command is not allowed while editing a cmdline: beep. - clearopbeep(oap); + clearopbeep(&s->oa); text_locked_msg(); goto normal_end; } - if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked()) + + if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked()) { goto normal_end; + } - /* - * In Visual/Select mode, a few keys are handled in a special way. - */ + // In Visual/Select mode, a few keys are handled in a special way. if (VIsual_active) { - /* when 'keymodel' contains "stopsel" may stop Select/Visual mode */ + // when 'keymodel' contains "stopsel" may stop Select/Visual mode if (km_stopsel && (nv_cmds[idx].cmd_flags & NV_STS) && !(mod_mask & MOD_MASK_SHIFT)) { @@ -702,14 +687,14 @@ getcount: redraw_curbuf_later(INVERTED); } - /* Keys that work different when 'keymodel' contains "startsel" */ + // Keys that work different when 'keymodel' contains "startsel" if (km_startsel) { if (nv_cmds[idx].cmd_flags & NV_SS) { - unshift_special(&ca); - idx = find_command(ca.cmdchar); + unshift_special(&s->ca); + idx = find_command(s->ca.cmdchar); if (idx < 0) { - /* Just in case */ - clearopbeep(oap); + // Just in case + clearopbeep(&s->oa); goto normal_end; } } else if ((nv_cmds[idx].cmd_flags & NV_SSS) @@ -721,97 +706,94 @@ getcount: if (curwin->w_p_rl && KeyTyped && !KeyStuffed && (nv_cmds[idx].cmd_flags & NV_RL)) { - /* Invert horizontal movements and operations. Only when typed by the - * user directly, not when the result of a mapping or "x" translated - * to "dl". */ - switch (ca.cmdchar) { - case 'l': ca.cmdchar = 'h'; break; - case K_RIGHT: ca.cmdchar = K_LEFT; break; - case K_S_RIGHT: ca.cmdchar = K_S_LEFT; break; - case K_C_RIGHT: ca.cmdchar = K_C_LEFT; break; - case 'h': ca.cmdchar = 'l'; break; - case K_LEFT: ca.cmdchar = K_RIGHT; break; - case K_S_LEFT: ca.cmdchar = K_S_RIGHT; break; - case K_C_LEFT: ca.cmdchar = K_C_RIGHT; break; - case '>': ca.cmdchar = '<'; break; - case '<': ca.cmdchar = '>'; break; - } - idx = find_command(ca.cmdchar); - } - - /* - * Get an additional character if we need one. - */ + // Invert horizontal movements and operations. Only when typed by the + // user directly, not when the result of a mapping or "x" translated + // to "dl". + switch (s->ca.cmdchar) { + case 'l': s->ca.cmdchar = 'h'; break; + case K_RIGHT: s->ca.cmdchar = K_LEFT; break; + case K_S_RIGHT: s->ca.cmdchar = K_S_LEFT; break; + case K_C_RIGHT: s->ca.cmdchar = K_C_LEFT; break; + case 'h': s->ca.cmdchar = 'l'; break; + case K_LEFT: s->ca.cmdchar = K_RIGHT; break; + case K_S_LEFT: s->ca.cmdchar = K_S_RIGHT; break; + case K_C_LEFT: s->ca.cmdchar = K_C_RIGHT; break; + case '>': s->ca.cmdchar = '<'; break; + case '<': s->ca.cmdchar = '>'; break; + } + idx = find_command(s->ca.cmdchar); + } + + // Get an additional character if we need one. if ((nv_cmds[idx].cmd_flags & NV_NCH) && (((nv_cmds[idx].cmd_flags & NV_NCH_NOP) == NV_NCH_NOP - && oap->op_type == OP_NOP) + && s->oa.op_type == OP_NOP) || (nv_cmds[idx].cmd_flags & NV_NCH_ALW) == NV_NCH_ALW - || (ca.cmdchar == 'q' - && oap->op_type == OP_NOP + || (s->ca.cmdchar == 'q' + && s->oa.op_type == OP_NOP && !Recording && !Exec_reg) - || ((ca.cmdchar == 'a' || ca.cmdchar == 'i') - && (oap->op_type != OP_NOP - || VIsual_active - )))) { - int *cp; - bool repl = false; /* get character for replace mode */ - bool lit = false; /* get extra character literally */ - bool langmap_active = false; /* using :lmap mappings */ - int lang; /* getting a text character */ + || ((s->ca.cmdchar == 'a' || s->ca.cmdchar == 'i') + && (s->oa.op_type != OP_NOP || VIsual_active)))) { + int *cp; + bool repl = false; // get character for replace mode + bool lit = false; // get extra character literally + bool langmap_active = false; // using :lmap mappings + int lang; // getting a text character ++no_mapping; - ++allow_keys; /* no mapping for nchar, but allow key codes */ - /* Don't generate a CursorHold event here, most commands can't handle - * it, e.g., nv_replace(), nv_csearch(). */ + ++allow_keys; // no mapping for nchar, but allow key codes + // Don't generate a CursorHold event here, most commands can't handle + // it, e.g., nv_replace(), nv_csearch(). did_cursorhold = true; - if (ca.cmdchar == 'g') { - /* - * For 'g' get the next character now, so that we can check for - * "gr", "g'" and "g`". - */ - ca.nchar = plain_vgetc(); - LANGMAP_ADJUST(ca.nchar, true); - need_flushbuf |= add_to_showcmd(ca.nchar); - if (ca.nchar == 'r' || ca.nchar == '\'' || ca.nchar == '`' - || ca.nchar == Ctrl_BSL) { - cp = &ca.extra_char; /* need to get a third character */ - if (ca.nchar != 'r') - lit = true; /* get it literally */ - else - repl = true; /* get it in replace mode */ - } else - cp = NULL; /* no third character needed */ + if (s->ca.cmdchar == 'g') { + // For 'g' get the next character now, so that we can check for + // "gr", "g'" and "g`". + s->ca.nchar = plain_vgetc(); + LANGMAP_ADJUST(s->ca.nchar, true); + need_flushbuf |= add_to_showcmd(s->ca.nchar); + if (s->ca.nchar == 'r' || s->ca.nchar == '\'' || s->ca.nchar == '`' + || s->ca.nchar == Ctrl_BSL) { + cp = &s->ca.extra_char; // need to get a third character + if (s->ca.nchar != 'r') { + lit = true; // get it literally + } else { + repl = true; // get it in replace mode + } + } else { + cp = NULL; // no third character needed + } } else { - if (ca.cmdchar == 'r') /* get it in replace mode */ + if (s->ca.cmdchar == 'r') { + // get it in replace mode repl = true; - cp = &ca.nchar; + } + cp = &s->ca.nchar; } lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); - /* - * Get a second or third character. - */ + // Get a second or third character. if (cp != NULL) { if (repl) { - State = REPLACE; /* pretend Replace mode */ - ui_cursor_shape(); /* show different cursor shape */ + State = REPLACE; // pretend Replace mode + ui_cursor_shape(); // show different cursor shape } if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) { - /* Allow mappings defined with ":lmap". */ + // Allow mappings defined with ":lmap". --no_mapping; --allow_keys; - if (repl) + if (repl) { State = LREPLACE; - else + } else { State = LANGMAP; + } langmap_active = true; } *cp = plain_vgetc(); if (langmap_active) { - /* Undo the decrement done above */ + // Undo the decrement done above ++no_mapping; ++allow_keys; State = NORMAL_BUSY; @@ -820,69 +802,69 @@ getcount: need_flushbuf |= add_to_showcmd(*cp); if (!lit) { - /* Typing CTRL-K gets a digraph. */ - if (*cp == Ctrl_K - && ((nv_cmds[idx].cmd_flags & NV_LANG) - || cp == &ca.extra_char) + // Typing CTRL-K gets a digraph. + if (*cp == Ctrl_K && ((nv_cmds[idx].cmd_flags & NV_LANG) + || cp == &s->ca.extra_char) && vim_strchr(p_cpo, CPO_DIGRAPH) == NULL) { c = get_digraph(false); if (c > 0) { *cp = c; - /* Guessing how to update showcmd here... */ + // Guessing how to update showcmd here... del_from_showcmd(3); need_flushbuf |= add_to_showcmd(*cp); } } - /* adjust chars > 127, except after "tTfFr" commands */ + // adjust chars > 127, except after "tTfFr" commands LANGMAP_ADJUST(*cp, !lang); - /* adjust Hebrew mapped char */ - if (p_hkmap && lang && KeyTyped) + // adjust Hebrew mapped char + if (p_hkmap && lang && KeyTyped) { *cp = hkmap(*cp); - /* adjust Farsi mapped char */ - if (p_fkmap && lang && KeyTyped) + } + // adjust Farsi mapped char + if (p_fkmap && lang && KeyTyped) { *cp = fkmap(*cp); + } } - /* - * When the next character is CTRL-\ a following CTRL-N means the - * command is aborted and we go to Normal mode. - */ - if (cp == &ca.extra_char - && ca.nchar == Ctrl_BSL - && (ca.extra_char == Ctrl_N || ca.extra_char == Ctrl_G)) { - ca.cmdchar = Ctrl_BSL; - ca.nchar = ca.extra_char; - idx = find_command(ca.cmdchar); - } else if ((ca.nchar == 'n' || ca.nchar == 'N') && ca.cmdchar == 'g') - ca.oap->op_type = get_op_type(*cp, NUL); - else if (*cp == Ctrl_BSL) { + // When the next character is CTRL-\ a following CTRL-N means the + // command is aborted and we go to Normal mode. + if (cp == &s->ca.extra_char + && s->ca.nchar == Ctrl_BSL + && (s->ca.extra_char == Ctrl_N || s->ca.extra_char == Ctrl_G)) { + s->ca.cmdchar = Ctrl_BSL; + s->ca.nchar = s->ca.extra_char; + idx = find_command(s->ca.cmdchar); + } else if ((s->ca.nchar == 'n' || s->ca.nchar == 'N') + && s->ca.cmdchar == 'g') { + s->ca.oap->op_type = get_op_type(*cp, NUL); + } else if (*cp == Ctrl_BSL) { long towait = (p_ttm >= 0 ? p_ttm : p_tm); - /* There is a busy wait here when typing "f" and then - * something different from CTRL-N. Can't be avoided. */ + // There is a busy wait here when typing "f" and then + // something different from CTRL-N. Can't be avoided. while ((c = vpeekc()) <= 0 && towait > 0L) { do_sleep(towait > 50L ? 50L : towait); towait -= 50L; } if (c > 0) { c = plain_vgetc(); - if (c != Ctrl_N && c != Ctrl_G) + if (c != Ctrl_N && c != Ctrl_G) { vungetc(c); - else { - ca.cmdchar = Ctrl_BSL; - ca.nchar = c; - idx = find_command(ca.cmdchar); + } else { + s->ca.cmdchar = Ctrl_BSL; + s->ca.nchar = c; + idx = find_command(s->ca.cmdchar); assert(idx >= 0); } } } - /* When getting a text character and the next character is a - * multi-byte character, it could be a composing character. - * However, don't wait for it to arrive. Also, do enable mapping, - * because if it's put back with vungetc() it's too late to apply - * mapping. */ + // When getting a text character and the next character is a + // multi-byte character, it could be a composing character. + // However, don't wait for it to arrive. Also, do enable mapping, + // because if it's put back with vungetc() it's too late to apply + // mapping. no_mapping--; while (enc_utf8 && lang && (c = vpeekc()) > 0 && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { @@ -890,10 +872,11 @@ getcount: if (!utf_iscomposing(c)) { vungetc(c); /* it wasn't, put it back */ break; - } else if (ca.ncharC1 == 0) - ca.ncharC1 = c; - else - ca.ncharC2 = c; + } else if (s->ca.ncharC1 == 0) { + s->ca.ncharC1 = c; + } else { + s->ca.ncharC2 = c; + } } no_mapping++; } @@ -901,40 +884,41 @@ getcount: --allow_keys; } - /* - * Flush the showcmd characters onto the screen so we can see them while - * the command is being executed. Only do this when the shown command was - * actually displayed, otherwise this will slow down a lot when executing - * mappings. - */ - if (need_flushbuf) + // Flush the showcmd characters onto the screen so we can see them while + // the command is being executed. Only do this when the shown command was + // actually displayed, otherwise this will slow down a lot when executing + // mappings. + if (need_flushbuf) { ui_flush(); - if (ca.cmdchar != K_IGNORE) + } + if (s->ca.cmdchar != K_IGNORE) { did_cursorhold = false; + } State = NORMAL; - if (ca.nchar == ESC) { - clearop(oap); - if (restart_edit == 0 && goto_im()) + if (s->ca.nchar == ESC) { + clearop(&s->oa); + if (restart_edit == 0 && goto_im()) { restart_edit = 'a'; + } goto normal_end; } - if (ca.cmdchar != K_IGNORE) { - msg_didout = false; /* don't scroll screen up for normal command */ + if (s->ca.cmdchar != K_IGNORE) { + msg_didout = false; // don't scroll screen up for normal command msg_col = 0; } - old_pos = curwin->w_cursor; /* remember where cursor was */ + old_pos = curwin->w_cursor; // remember where cursor was - /* When 'keymodel' contains "startsel" some keys start Select/Visual - * mode. */ + // When 'keymodel' contains "startsel" some keys start Select/Visual + // mode. if (!VIsual_active && km_startsel) { if (nv_cmds[idx].cmd_flags & NV_SS) { start_selection(); - unshift_special(&ca); - idx = find_command(ca.cmdchar); + unshift_special(&s->ca); + idx = find_command(s->ca.cmdchar); } else if ((nv_cmds[idx].cmd_flags & NV_SSS) && (mod_mask & MOD_MASK_SHIFT)) { start_selection(); @@ -942,164 +926,148 @@ getcount: } } - /* - * Execute the command! - * Call the command function found in the commands table. - */ - ca.arg = nv_cmds[idx].cmd_arg; - (nv_cmds[idx].cmd_func)(&ca); + // Execute the command! + // Call the command function found in the commands table. + s->ca.arg = nv_cmds[idx].cmd_arg; + (nv_cmds[idx].cmd_func)(&s->ca); - /* - * If we didn't start or finish an operator, reset oap->regname, unless we - * need it later. - */ + // If we didn't start or finish an operator, reset oap->regname, unless we + // need it later. if (!finish_op - && !oap->op_type + && !s->oa.op_type && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) { - clearop(oap); + 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". */ - if (old_mapped_len > 0) + // Get the length of mapped chars again after typing a count, second + // character or "z333". + if (old_mapped_len > 0) { old_mapped_len = typebuf_maplen(); + } - /* - * If an operation is pending, handle it... - */ - do_pending_operator(&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))) - && oap->regname == 0 - && !(ca.retval & CA_COMMAND_BUSY) + // 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 - && oap->op_type == OP_NOP) { + && s->oa.op_type == OP_NOP) { int save_State = State; - /* Draw the cursor with the right shape here */ - if (restart_edit != 0) + // 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 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 */ + // 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 */ + // 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 */ + 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. - */ + // Finish up after executing a Normal mode command. normal_end: msg_nowait = false; - /* Reset finish_op, in case it was set */ + // Reset finish_op, in case it was set 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 (c || ca.cmdchar == 'r') { - ui_cursor_shape(); /* may show different cursor shape */ + // Redraw the cursor with another shape, if we were in Operator-pending + // mode or did a replace command. + if (c || s->ca.cmdchar == 'r') { + ui_cursor_shape(); // may show different cursor shape } - if (oap->op_type == OP_NOP && oap->regname == 0 - && ca.cmdchar != K_CURSORHOLD - ) + if (s->oa.op_type == OP_NOP && s->oa.regname == 0 + && s->ca.cmdchar != K_CURSORHOLD) { clear_showcmd(); + } - checkpcmark(); /* check if we moved since setting pcmark */ - xfree(ca.searchbuf); + checkpcmark(); // check if we moved since setting pcmark + xfree(s->ca.searchbuf); - if (has_mbyte) + if (has_mbyte) { mb_adjust_cursor(); + } - if (curwin->w_p_scb && toplevel) { - validate_cursor(); /* may need to update w_leftcol */ + if (curwin->w_p_scb && s->toplevel) { + validate_cursor(); // may need to update w_leftcol do_check_scrollbind(true); } - if (curwin->w_p_crb && toplevel) { - validate_cursor(); /* may need to update w_leftcol */ + 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 ( oap->op_type == OP_NOP + // 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) - && !(ca.retval & CA_COMMAND_BUSY) + && !(s->ca.retval & CA_COMMAND_BUSY) && stuff_empty() - && oap->regname == 0) { + && 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 - ) + if (restart_edit != 0 && !VIsual_active && old_mapped_len == 0) { (void)edit(restart_edit, false, 1L); + } } - if (restart_VIsual_select == 2) + if (restart_VIsual_select == 2) { restart_VIsual_select = 1; + } - /* Save count before an operator for next time. */ - opcount = ca.opcount; + // Save count before an operator for next time + opcount = s->ca.opcount; return 1; } -- cgit From e5165bae1139221ef752bccd582c7bd7474e6747 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Mon, 5 Oct 2015 10:13:18 -0300 Subject: input: Remove CURSORHOLD key Refactor input.c, normal.c and edit.c to use the K_EVENT special key to trigger the CURSORHOLD event. In normal and edit mode, K_EVENT is treated as K_CURSORHOLD, which enables better handling of arbitrary actions in those states(eg: In normal mode the previous operator counts will be restored). Also fix a test in vim_spec.lua. The test had a wrong assumption: cmdheight is only used to determine when the press enter screen will be shown, not to limit how many lines or control pagination. --- src/nvim/edit.c | 23 +++++++++-------------- src/nvim/keymap.c | 1 - src/nvim/keymap.h | 2 -- src/nvim/normal.c | 38 ++++++++++++-------------------------- src/nvim/normal.h | 4 ++-- src/nvim/os/input.c | 29 ++++++++++++++++++++--------- 6 files changed, 43 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b2f9601f82..67dbf8483b 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -626,14 +626,9 @@ edit ( } while (c == K_IGNORE); input_disable_events(); - if (c == K_EVENT) { - c = lastc; - queue_process_events(loop.events); - continue; - } - - /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */ - did_cursorhold = TRUE; + // Don't want K_EVENT with cursorhold for the second key, e.g., after + // CTRL-V. + did_cursorhold = true; if (p_hkmap && KeyTyped) c = hkmap(c); /* Hebrew mode mapping */ @@ -974,9 +969,8 @@ doESCkey: case K_IGNORE: /* Something mapped to nothing */ break; - case K_CURSORHOLD: /* Didn't type something for a while. */ - apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf); - did_cursorhold = TRUE; + case K_EVENT: // some event + queue_process_events(loop.events); break; case K_HOME: /* */ @@ -1223,9 +1217,10 @@ normalchar: break; } /* end of switch (c) */ - /* If typed something may trigger CursorHoldI again. */ - if (c != K_CURSORHOLD) - did_cursorhold = FALSE; + // If typed something may trigger CursorHoldI again. + if (c != K_EVENT) { + did_cursorhold = false; + } /* If the cursor was moved we didn't just insert a space */ if (arrow_used) diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index bf4f5e8c4d..9d656276ec 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -283,7 +283,6 @@ static struct key_name_entry { {K_ZERO, (char_u *)"Nul"}, {K_SNR, (char_u *)"SNR"}, {K_PLUG, (char_u *)"Plug"}, - {K_CURSORHOLD, (char_u *)"CursorHold"}, {K_PASTE, (char_u *)"Paste"}, {0, NULL} }; diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index 119bff943a..d2d96c6149 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -242,7 +242,6 @@ enum key_extra { , KE_X2RELEASE , KE_DROP /* DnD data is available */ - , KE_CURSORHOLD /* CursorHold event */ , KE_NOP /* doesn't do something */ , KE_FOCUSGAINED /* focus gained */ , KE_FOCUSLOST /* focus lost */ @@ -437,7 +436,6 @@ enum key_extra { #define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED) #define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST) -#define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD) #define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT) #define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE) diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 11ef093ee7..740c30d323 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -336,7 +336,7 @@ static const struct nv_cmd { {K_SELECT, nv_select, 0, 0}, {K_F8, farsi_fkey, 0, 0}, {K_F9, farsi_fkey, 0, 0}, - {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0}, + {K_EVENT, nv_event, NV_KEEPREG, 0}, }; /* Number of commands in nv_cmds[]. */ @@ -492,8 +492,8 @@ static void normal_prepare(NormalState *s) s->set_prevcount = true; } - // Restore counts from before receiving K_CURSORHOLD. This means after - // typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not + // Restore counts from before receiving K_EVENT. This means after + // typing "3", handling K_EVENT and then typing "2" we get "32", not // "3 * 2". if (s->oa.prev_opcount > 0 || s->oa.prev_count0 > 0) { s->ca.opcount = s->oa.prev_opcount; @@ -616,9 +616,9 @@ getcount: } } - if (c == K_CURSORHOLD) { + if (c == K_EVENT) { // Save the count values so that ca.opcount and ca.count0 are exactly - // the same when coming back here after handling K_CURSORHOLD. + // the same when coming back here after handling K_EVENT. s->oa.prev_opcount = s->ca.opcount; s->oa.prev_count0 = s->ca.count0; } else if (s->ca.opcount != 0) { @@ -891,7 +891,7 @@ getcount: if (need_flushbuf) { ui_flush(); } - if (s->ca.cmdchar != K_IGNORE) { + if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_EVENT) { did_cursorhold = false; } @@ -1022,7 +1022,7 @@ normal_end: } if (s->oa.op_type == OP_NOP && s->oa.regname == 0 - && s->ca.cmdchar != K_CURSORHOLD) { + && s->ca.cmdchar != K_EVENT) { clear_showcmd(); } @@ -3147,7 +3147,7 @@ bool add_to_showcmd(int c) K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE, K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT, K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE, - K_CURSORHOLD, + K_EVENT, 0 }; @@ -7567,16 +7567,11 @@ static void nv_