From 596002766519c399ac426bcb5923c996caf12d11 Mon Sep 17 00:00:00 2001 From: "Andy K. Massimino" Date: Sat, 9 Oct 2021 13:04:25 -0400 Subject: [PATCH] Add test for where feature --- test/new/test-where/LICENSE | 78 ++++ test/new/test-where/Makefile | 10 + test/new/test-where/normal.c | 811 +++++++++++++++++++++++++++++++++ test/new/test-where/test.vim | 24 + test/new/test-where/test1.good | 1 + test/new/test-where/test2.good | 1 + test/new/test-where/test3.good | 4 + 7 files changed, 929 insertions(+) create mode 100644 test/new/test-where/LICENSE create mode 100644 test/new/test-where/Makefile create mode 100644 test/new/test-where/normal.c create mode 100644 test/new/test-where/test.vim create mode 100644 test/new/test-where/test1.good create mode 100644 test/new/test-where/test2.good create mode 100644 test/new/test-where/test3.good diff --git a/test/new/test-where/LICENSE b/test/new/test-where/LICENSE new file mode 100644 index 0000000..ecfbe55 --- /dev/null +++ b/test/new/test-where/LICENSE @@ -0,0 +1,78 @@ +VIM LICENSE + +I) There are no restrictions on distributing unmodified copies of Vim except + that they must include this license text. You can also distribute + unmodified parts of Vim, likewise unrestricted except that they must + include this license text. You are also allowed to include executables + that you made from the unmodified Vim sources, plus your own usage + examples and Vim scripts. + +II) It is allowed to distribute a modified (or extended) version of Vim, + including executables and/or source code, when the following four + conditions are met: + 1) This license text must be included unmodified. + 2) The modified Vim must be distributed in one of the following five ways: + a) If you make changes to Vim yourself, you must clearly describe in + the distribution how to contact you. When the maintainer asks you + (in any way) for a copy of the modified Vim you distributed, you + must make your changes, including source code, available to the + maintainer without fee. The maintainer reserves the right to + include your changes in the official version of Vim. What the + maintainer will do with your changes and under what license they + will be distributed is negotiable. If there has been no negotiation + then this license, or a later version, also applies to your changes. + The current maintainer is Bram Moolenaar . If this + changes it will be announced in appropriate places (most likely + vim.sf.net, www.vim.org and/or comp.editors). When it is completely + impossible to contact the maintainer, the obligation to send him + your changes ceases. Once the maintainer has confirmed that he has + received your changes they will not have to be sent again. + b) If you have received a modified Vim that was distributed as + mentioned under a) you are allowed to further distribute it + unmodified, as mentioned at I). If you make additional changes the + text under a) applies to those changes. + c) Provide all the changes, including source code, with every copy of + the modified Vim you distribute. This may be done in the form of a + context diff. You can choose what license to use for new code you + add. The changes and their license must not restrict others from + making their own changes to the official version of Vim. + d) When you have a modified Vim which includes changes as mentioned + under c), you can distribute it without the source code for the + changes if the following three conditions are met: + - The license that applies to the changes permits you to distribute + the changes to the Vim maintainer without fee or restriction, and + permits the Vim maintainer to include the changes in the official + version of Vim without fee or restriction. + - You keep the changes for at least three years after last + distributing the corresponding modified Vim. When the maintainer + or someone who you distributed the modified Vim to asks you (in + any way) for the changes within this period, you must make them + available to him. + - You clearly describe in the distribution how to contact you. This + contact information must remain valid for at least three years + after last distributing the corresponding modified Vim, or as long + as possible. + e) When the GNU General Public License (GPL) applies to the changes, + you can distribute the modified Vim under the GNU GPL version 2 or + any later version. + 3) A message must be added, at least in the output of the ":version" + command and in the intro screen, such that the user of the modified Vim + is able to see that it was modified. When distributing as mentioned + under 2)e) adding the message is only required for as far as this does + not conflict with the license used for the changes. + 4) The contact information as required under 2)a) and 2)d) must not be + removed or changed, except that the person himself can make + corrections. + +III) If you distribute a modified version of Vim, you are encouraged to use + the Vim license for your changes and make them available to the + maintainer, including the source code. The preferred way to do this is + by e-mail or by uploading the files to a server and e-mailing the URL. + If the number of changes is small (e.g., a modified Makefile) e-mailing a + context diff will do. The e-mail address to be used is + + +IV) It is not allowed to remove this license from the distribution of the Vim + sources, parts of it or from a modified version. You may use this + license for previous Vim releases instead of the license that they came + with, at your option. diff --git a/test/new/test-where/Makefile b/test/new/test-where/Makefile new file mode 100644 index 0000000..5748c84 --- /dev/null +++ b/test/new/test-where/Makefile @@ -0,0 +1,10 @@ +.PHONY: test + +MYVIM ?= nvim --headless + +INMAKE := 1 +export INMAKE + +test: + $(MYVIM) -u test.vim + rm *.out diff --git a/test/new/test-where/normal.c b/test/new/test-where/normal.c new file mode 100644 index 0000000..eba8ef5 --- /dev/null +++ b/test/new/test-where/normal.c @@ -0,0 +1,811 @@ + void +normal_cmd( + oparg_T *oap, + int toplevel UNUSED) // TRUE when called from main() +{ + cmdarg_T ca; // command arguments + int c; + int ctrl_w = FALSE; // got CTRL-W command + int old_col = curwin->w_curswant; +#ifdef FEAT_CMDL_INFO + int need_flushbuf; // need to call out_flush() +#endif + pos_T old_pos; // cursor position before command + int mapped_len; + static int old_mapped_len = 0; + int idx; +#ifdef FEAT_EVAL + int set_prevcount = FALSE; +#endif + int save_did_cursorhold = did_cursorhold; + + CLEAR_FIELD(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). + */ +#ifdef CURSOR_SHAPE + c = finish_op; +#endif + finish_op = (oap->op_type != OP_NOP); +#ifdef CURSOR_SHAPE + if (finish_op != c) + { + ui_cursor_shape(); // may show different cursor shape +# ifdef FEAT_MOUSESHAPE + update_mouseshape(-1); +# endif + } +#endif + + // When not finishing an operator and no register name typed, reset the + // count. + if (!finish_op && !oap->regname) + { + ca.opcount = 0; +#ifdef FEAT_EVAL + set_prevcount = TRUE; +#endif + } + + // 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; + } + + mapped_len = typebuf_maplen(); + + State = NORMAL_BUSY; +#ifdef USE_ON_FLY_SCROLL + dont_scroll = FALSE; // allow scrolling here +#endif + +#ifdef FEAT_EVAL + // 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); +#endif + + /* + * Get the command character from the user. + */ + c = safe_vgetc(); + LANGMAP_ADJUST(c, get_real_state() != SELECTMODE); + + /* + * 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)) + old_mapped_len = typebuf_maplen(); + + if (c == NUL) + c = K_ZERO; + + /* + * 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. + ins_char_typebuf(vgetc_char, vgetc_mod_mask); + if (restart_edit != 0) + c = 'd'; + else + c = 'c'; + msg_nowait = TRUE; // don't delay going to insert mode + old_mapped_len = 0; // do go to Insert mode + } + +#ifdef FEAT_CMDL_INFO + need_flushbuf = add_to_showcmd(c); +#endif + +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'))) + { + if (c == K_DEL || c == K_KDEL) + { + ca.count0 /= 10; +#ifdef FEAT_CMDL_INFO + del_from_showcmd(4); // delete the digit and ~@% +#endif + } + else + ca.count0 = ca.count0 * 10 + (c - '0'); + if (ca.count0 < 0) // overflow + ca.count0 = 999999999L; +#ifdef FEAT_EVAL + // 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); +#endif + if (ctrl_w) + { + ++no_mapping; + ++allow_keys; // no mapping for nchar, but keys + } + ++no_zero_mapping; // don't map zero here + c = plain_vgetc(); + LANGMAP_ADJUST(c, TRUE); + --no_zero_mapping; + if (ctrl_w) + { + --no_mapping; + --allow_keys; + } +#ifdef FEAT_CMDL_INFO + need_flushbuf |= add_to_showcmd(c); +#endif + } + + /* + * If we got CTRL-W there may be a/another count + */ + if (c == Ctrl_W && !ctrl_w && oap->op_type == OP_NOP) + { + ctrl_w = TRUE; + ca.opcount = ca.count0; // remember first count + ca.count0 = 0; + ++no_mapping; + ++allow_keys; // no mapping for nchar, but keys + c = plain_vgetc(); // get next character + LANGMAP_ADJUST(c, TRUE); + --no_mapping; + --allow_keys; +#ifdef FEAT_CMDL_INFO + need_flushbuf |= add_to_showcmd(c); +#endif + 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; + if (ca.count0 < 0) // overflow + ca.count0 = 999999999L; + } + + /* + * 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); + +#ifdef FEAT_EVAL + /* + * 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); +#endif + + /* + * 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); + if (idx < 0) + { + // Not a known command: beep. + clearopbeep(oap); + 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); + text_locked_msg(); + goto normal_end; + } + 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. + */ + if (VIsual_active) + { + // when 'keymodel' contains "stopsel" may stop Select/Visual mode + if (km_stopsel + && (nv_cmds[idx].cmd_flags & NV_STS) + && !(mod_mask & MOD_MASK_SHIFT)) + { + end_visual_mode(); + redraw_curbuf_later(INVERTED); + } + + // 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); + if (idx < 0) + { + // Just in case + clearopbeep(oap); + goto normal_end; + } + } + else if ((nv_cmds[idx].cmd_flags & NV_SSS) + && (mod_mask & MOD_MASK_SHIFT)) + mod_mask &= ~MOD_MASK_SHIFT; + } + } + +#ifdef FEAT_RIGHTLEFT + 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); + } +#endif + + /* + * 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) + || (nv_cmds[idx].cmd_flags & NV_NCH_ALW) == NV_NCH_ALW + || (ca.cmdchar == 'q' + && oap->op_type == OP_NOP + && reg_recording == 0 + && reg_executing == 0) + || ((ca.cmdchar == 'a' || ca.cmdchar == 'i') + && (oap->op_type != OP_NOP || VIsual_active)))) + { + int *cp; + int repl = FALSE; // get character for replace mode + int lit = FALSE; // get extra character literally + int langmap_active = FALSE; // using :lmap mappings + int lang; // getting a text character +#ifdef HAVE_INPUT_METHOD + int save_smd; // saved value of p_smd +#endif + + ++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(). + 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); +#ifdef FEAT_CMDL_INFO + need_flushbuf |= add_to_showcmd(ca.nchar); +#endif + 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 + } + else + { + if (ca.cmdchar == 'r') // get it in replace mode + repl = TRUE; + cp = &ca.nchar; + } + lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); + + /* + * Get a second or third character. + */ + if (cp != NULL) + { + if (repl) + { + State = REPLACE; // pretend Replace mode +#ifdef CURSOR_SHAPE + ui_cursor_shape(); // show different cursor shape +#endif + } + if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) + { + // Allow mappings defined with ":lmap". + --no_mapping; + --allow_keys; + if (repl) + State = LREPLACE; + else + State = LANGMAP; + langmap_active = TRUE; + } +#ifdef HAVE_INPUT_METHOD + save_smd = p_smd; + p_smd = FALSE; // Don't let the IM code show the mode here + if (lang && curbuf->b_p_iminsert == B_IMODE_IM) + im_set_active(TRUE); +#endif + if ((State & INSERT) && !p_ek) + { +#ifdef FEAT_JOB_CHANNEL + ch_log_output = TRUE; +#endif + // Disable bracketed paste and modifyOtherKeys here, we won't + // recognize the escape sequences with 'esckeys' off. + out_str(T_BD); + out_str(T_CTE); + } + + *cp = plain_vgetc(); + + if ((State & INSERT) && !p_ek) + { +#ifdef FEAT_JOB_CHANNEL + ch_log_output = TRUE; +#endif + // Re-enable bracketed paste mode and modifyOtherKeys + out_str(T_BE); + out_str(T_CTI); + } + + if (langmap_active) + { + // Undo the decrement done above + ++no_mapping; + ++allow_keys; + State = NORMAL_BUSY; + } +#ifdef HAVE_INPUT_METHOD + if (lang) + { + if (curbuf->b_p_iminsert != B_IMODE_LMAP) + im_save_status(&curbuf->b_p_iminsert); + im_set_active(FALSE); + } + p_smd = save_smd; +#endif + State = NORMAL_BUSY; +#ifdef FEAT_CMDL_INFO + need_flushbuf |= add_to_showcmd(*cp); +#endif + + if (!lit) + { +#ifdef FEAT_DIGRAPHS + // Typing CTRL-K gets a digraph. + if (*cp == Ctrl_K + && ((nv_cmds[idx].cmd_flags & NV_LANG) + || cp == &ca.extra_char) + && vim_strchr(p_cpo, CPO_DIGRAPH) == NULL) + { + c = get_digraph(FALSE); + if (c > 0) + { + *cp = c; +# ifdef FEAT_CMDL_INFO + // Guessing how to update showcmd here... + del_from_showcmd(3); + need_flushbuf |= add_to_showcmd(*cp); +# endif + } + } +#endif + + // adjust chars > 127, except after "tTfFr" commands + LANGMAP_ADJUST(*cp, !lang); +#ifdef FEAT_RIGHTLEFT + // adjust Hebrew mapped char + if (p_hkmap && lang && KeyTyped) + *cp = hkmap(*cp); +#endif + } + + /* + * 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) + { + 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. + while ((c = vpeekc()) <= 0 && towait > 0L) + { + do_sleep(towait > 50L ? 50L : towait, FALSE); + towait -= 50L; + } + if (c > 0) + { + c = plain_vgetc(); + if (c != Ctrl_N && c != Ctrl_G) + vungetc(c); + else + { + ca.cmdchar = Ctrl_BSL; + ca.nchar = c; + idx = find_command(ca.cmdchar); + } + } + } + + // 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)) + { + c = plain_vgetc(); + 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; + } + ++no_mapping; + } + --no_mapping; + --allow_keys; + } + +#ifdef FEAT_CMDL_INFO + /* + * 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) + out_flush(); +#endif + if (ca.cmdchar != K_IGNORE) + { + if (ex_normal_busy) + did_cursorhold = save_did_cursorhold; + else + did_cursorhold = FALSE; + } + + State = NORMAL; + + if (ca.nchar == ESC) + { + clearop(oap); + 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 + msg_col = 0; + } + + old_pos = curwin->w_cursor; // remember where cursor was + + // 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); + } + else if ((nv_cmds[idx].cmd_flags & NV_SSS) + && (mod_mask & MOD_MASK_SHIFT)) + { + start_selection(); + mod_mask &= ~MOD_MASK_SHIFT; + } + } + + /* + * 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); + + /* + * If we didn't start or finish an operator, reset oap->regname, unless we + * need it later. + */ + if (!finish_op + && !oap->op_type + && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) + { + clearop(oap); +#ifdef FEAT_EVAL + reset_reg_var(); +#endif + } + + // 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. But not for K_IGNORE or + * K_MOUSEMOVE. + */ + if (ca.cmdchar != K_IGNORE && ca.cmdchar != K_MOUSEMOVE) + 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) + && stuff_empty() + && typebuf_typed() + && emsg_silent == 0 + && !in_assert_fails + && !did_wait_return + && oap->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. + // First update w_topline. + setcursor(); + update_screen(0); + // now reset it, otherwise it's put in the history again + keep_msg = kmsg; + + kmsg = vim_strsave(keep_msg); + if (kmsg != NULL) + { + msg_attr((char *)kmsg, keep_msg_attr); + vim_free(kmsg); + } + } + setcursor(); +#ifdef CURSOR_SHAPE + ui_cursor_shape(); // may show different cursor shape +#endif + cursor_on(); + out_flush(); + if (msg_scroll || emsg_on_display) + ui_delay(1003L, TRUE); // wait at least one second + ui_delay(3003L, 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; + +#ifdef FEAT_EVAL + if (finish_op) + reset_reg_var(); +#endif + + // Reset finish_op, in case it was set +#ifdef CURSOR_SHAPE + c = finish_op; +#endif + finish_op = FALSE; +#ifdef CURSOR_SHAPE + // 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 +# ifdef FEAT_MOUSESHAPE + update_mouseshape(-1); +# endif + } +#endif + +#ifdef FEAT_CMDL_INFO + if (oap->op_type == OP_NOP && oap->regname == 0 + && ca.cmdchar != K_CURSORHOLD) + clear_showcmd(); +#endif + + checkpcmark(); // check if we moved since setting pcmark + vim_free(ca.searchbuf); + + if (has_mbyte) + mb_adjust_cursor(); + + if (curwin->w_p_scb && 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 + do_check_cursorbind(); + } + +#ifdef FEAT_TERMINAL + // don't go to Insert mode if a terminal has a running job + if (term_job_running(curbuf->b_term)) + restart_edit = 0; +#endif + + /* + * 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 + && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0) + || restart_VIsual_select == 1) + && !(ca.retval & CA_COMMAND_BUSY) + && stuff_empty() + && oap->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 = ca.opcount; +} diff --git a/test/new/test-where/test.vim b/test/new/test-where/test.vim new file mode 100644 index 0000000..ce24b19 --- /dev/null +++ b/test/new/test-where/test.vim @@ -0,0 +1,24 @@ +set nocompatible +source ../common/bootstrap.vim + +edit +161 normal.c + +redir! > test1.out + sil MatchupWhereAmI? +redir END + +redir! > test2.out + normal! j + sil MatchupWhereAmI? +redir END + +redir! > test3.out + normal! k + sil MatchupWhereAmI?? +redir END + +call assert_equal(readfile('test1.out'), readfile('test1.good')) +call assert_equal(readfile('test2.out'), readfile('test2.good')) +call assert_equal(readfile('test3.out'), readfile('test3.good')) + +call matchup#test#finished() diff --git a/test/new/test-where/test1.good b/test/new/test-where/test1.good new file mode 100644 index 0000000..67f722f --- /dev/null +++ b/test/new/test-where/test1.good @@ -0,0 +1 @@ +match-up: loading...normal_cmd( … { ▶ if (!(VIsual … { ▶ while ( ( … { ▶ if (ctrl_w) … { diff --git a/test/new/test-where/test2.good b/test/new/test-where/test2.good new file mode 100644 index 0000000..784bab3 --- /dev/null +++ b/test/new/test-where/test2.good @@ -0,0 +1 @@ +match-up: loading...normal_cmd( … { ▶ if (!(VIsual … { ▶ while ( ( … { ▶ if (ctrl_w) … { \ No newline at end of file diff --git a/test/new/test-where/test3.good b/test/new/test-where/test3.good new file mode 100644 index 0000000..ec292e9 --- /dev/null +++ b/test/new/test-where/test3.good @@ -0,0 +1,4 @@ +match-up: loading...normal_cmd( … { + if (!(VIsual_active && VIsual_select)) … { + while ( (c >= '1' && c <= '9') … { + if (ctrl_w) … { \ No newline at end of file