1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 /* 10 * normal.c: Contains the main routine for processing characters in command 11 * mode. Communicates closely with the code in ops.c to handle 12 * the operators. 13 */ 14 15 #include "vim.h" 16 17 static int VIsual_mode_orig = NUL; // saved Visual mode 18 static int restart_VIsual_select = 0; 19 20 #ifdef FEAT_EVAL 21 static void set_vcount_ca(cmdarg_T *cap, int *set_prevcount); 22 #endif 23 static int nv_compare(const void *s1, const void *s2); 24 static void unshift_special(cmdarg_T *cap); 25 #ifdef FEAT_CMDL_INFO 26 static void del_from_showcmd(int); 27 #endif 28 29 /* 30 * nv_*(): functions called to handle Normal and Visual mode commands. 31 * n_*(): functions called to handle Normal mode commands. 32 * v_*(): functions called to handle Visual mode commands. 33 */ 34 static void nv_ignore(cmdarg_T *cap); 35 static void nv_nop(cmdarg_T *cap); 36 static void nv_error(cmdarg_T *cap); 37 static void nv_help(cmdarg_T *cap); 38 static void nv_addsub(cmdarg_T *cap); 39 static void nv_page(cmdarg_T *cap); 40 static void nv_zet(cmdarg_T *cap); 41 #ifdef FEAT_GUI 42 static void nv_ver_scrollbar(cmdarg_T *cap); 43 static void nv_hor_scrollbar(cmdarg_T *cap); 44 #endif 45 #ifdef FEAT_GUI_TABLINE 46 static void nv_tabline(cmdarg_T *cap); 47 static void nv_tabmenu(cmdarg_T *cap); 48 #endif 49 static void nv_exmode(cmdarg_T *cap); 50 static void nv_colon(cmdarg_T *cap); 51 static void nv_ctrlg(cmdarg_T *cap); 52 static void nv_ctrlh(cmdarg_T *cap); 53 static void nv_clear(cmdarg_T *cap); 54 static void nv_ctrlo(cmdarg_T *cap); 55 static void nv_hat(cmdarg_T *cap); 56 static void nv_Zet(cmdarg_T *cap); 57 static void nv_ident(cmdarg_T *cap); 58 static void nv_tagpop(cmdarg_T *cap); 59 static void nv_scroll(cmdarg_T *cap); 60 static void nv_right(cmdarg_T *cap); 61 static void nv_left(cmdarg_T *cap); 62 static void nv_up(cmdarg_T *cap); 63 static void nv_down(cmdarg_T *cap); 64 static void nv_end(cmdarg_T *cap); 65 static void nv_dollar(cmdarg_T *cap); 66 static void nv_search(cmdarg_T *cap); 67 static void nv_next(cmdarg_T *cap); 68 static int normal_search(cmdarg_T *cap, int dir, char_u *pat, int opt, int *wrapped); 69 static void nv_csearch(cmdarg_T *cap); 70 static void nv_brackets(cmdarg_T *cap); 71 static void nv_percent(cmdarg_T *cap); 72 static void nv_brace(cmdarg_T *cap); 73 static void nv_mark(cmdarg_T *cap); 74 static void nv_findpar(cmdarg_T *cap); 75 static void nv_undo(cmdarg_T *cap); 76 static void nv_kundo(cmdarg_T *cap); 77 static void nv_Replace(cmdarg_T *cap); 78 static void nv_replace(cmdarg_T *cap); 79 static void nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos); 80 static void v_visop(cmdarg_T *cap); 81 static void nv_subst(cmdarg_T *cap); 82 static void nv_abbrev(cmdarg_T *cap); 83 static void nv_optrans(cmdarg_T *cap); 84 static void nv_gomark(cmdarg_T *cap); 85 static void nv_pcmark(cmdarg_T *cap); 86 static void nv_regname(cmdarg_T *cap); 87 static void nv_visual(cmdarg_T *cap); 88 static void n_start_visual_mode(int c); 89 static void nv_window(cmdarg_T *cap); 90 static void nv_suspend(cmdarg_T *cap); 91 static void nv_g_cmd(cmdarg_T *cap); 92 static void nv_dot(cmdarg_T *cap); 93 static void nv_redo(cmdarg_T *cap); 94 static void nv_Undo(cmdarg_T *cap); 95 static void nv_tilde(cmdarg_T *cap); 96 static void nv_operator(cmdarg_T *cap); 97 #ifdef FEAT_EVAL 98 static void set_op_var(int optype); 99 #endif 100 static void nv_lineop(cmdarg_T *cap); 101 static void nv_home(cmdarg_T *cap); 102 static void nv_pipe(cmdarg_T *cap); 103 static void nv_bck_word(cmdarg_T *cap); 104 static void nv_wordcmd(cmdarg_T *cap); 105 static void nv_beginline(cmdarg_T *cap); 106 static void adjust_cursor(oparg_T *oap); 107 static void adjust_for_sel(cmdarg_T *cap); 108 static void nv_select(cmdarg_T *cap); 109 static void nv_goto(cmdarg_T *cap); 110 static void nv_normal(cmdarg_T *cap); 111 static void nv_esc(cmdarg_T *oap); 112 static void nv_edit(cmdarg_T *cap); 113 static void invoke_edit(cmdarg_T *cap, int repl, int cmd, int startln); 114 #ifdef FEAT_TEXTOBJ 115 static void nv_object(cmdarg_T *cap); 116 #endif 117 static void nv_record(cmdarg_T *cap); 118 static void nv_at(cmdarg_T *cap); 119 static void nv_halfpage(cmdarg_T *cap); 120 static void nv_join(cmdarg_T *cap); 121 static void nv_put(cmdarg_T *cap); 122 static void nv_put_opt(cmdarg_T *cap, int fix_indent); 123 static void nv_open(cmdarg_T *cap); 124 #ifdef FEAT_NETBEANS_INTG 125 static void nv_nbcmd(cmdarg_T *cap); 126 #endif 127 #ifdef FEAT_DND 128 static void nv_drop(cmdarg_T *cap); 129 #endif 130 static void nv_cursorhold(cmdarg_T *cap); 131 132 static char *e_noident = N_("E349: No identifier under cursor"); 133 134 /* 135 * Function to be called for a Normal or Visual mode command. 136 * The argument is a cmdarg_T. 137 */ 138 typedef void (*nv_func_T)(cmdarg_T *cap); 139 140 // Values for cmd_flags. 141 #define NV_NCH 0x01 // may need to get a second char 142 #define NV_NCH_NOP (0x02|NV_NCH) // get second char when no operator pending 143 #define NV_NCH_ALW (0x04|NV_NCH) // always get a second char 144 #define NV_LANG 0x08 // second char needs language adjustment 145 146 #define NV_SS 0x10 // may start selection 147 #define NV_SSS 0x20 // may start selection with shift modifier 148 #define NV_STS 0x40 // may stop selection without shift modif. 149 #define NV_RL 0x80 // 'rightleft' modifies command 150 #define NV_KEEPREG 0x100 // don't clear regname 151 #define NV_NCW 0x200 // not allowed in command-line window 152 153 /* 154 * Generally speaking, every Normal mode command should either clear any 155 * pending operator (with *clearop*()), or set the motion type variable 156 * oap->motion_type. 157 * 158 * When a cursor motion command is made, it is marked as being a character or 159 * line oriented motion. Then, if an operator is in effect, the operation 160 * becomes character or line oriented accordingly. 161 */ 162 163 /* 164 * This table contains one entry for every Normal or Visual mode command. 165 * The order doesn't matter, init_normal_cmds() will create a sorted index. 166 * It is faster when all keys from zero to '~' are present. 167 */ 168 static const struct nv_cmd 169 { 170 int cmd_char; // (first) command character 171 nv_func_T cmd_func; // function for this command 172 short_u cmd_flags; // NV_ flags 173 short cmd_arg; // value for ca.arg 174 } nv_cmds[] = 175 { 176 {NUL, nv_error, 0, 0}, 177 {Ctrl_A, nv_addsub, 0, 0}, 178 {Ctrl_B, nv_page, NV_STS, BACKWARD}, 179 {Ctrl_C, nv_esc, 0, TRUE}, 180 {Ctrl_D, nv_halfpage, 0, 0}, 181 {Ctrl_E, nv_scroll_line, 0, TRUE}, 182 {Ctrl_F, nv_page, NV_STS, FORWARD}, 183 {Ctrl_G, nv_ctrlg, 0, 0}, 184 {Ctrl_H, nv_ctrlh, 0, 0}, 185 {Ctrl_I, nv_pcmark, 0, 0}, 186 {NL, nv_down, 0, FALSE}, 187 {Ctrl_K, nv_error, 0, 0}, 188 {Ctrl_L, nv_clear, 0, 0}, 189 {CAR, nv_down, 0, TRUE}, 190 {Ctrl_N, nv_down, NV_STS, FALSE}, 191 {Ctrl_O, nv_ctrlo, 0, 0}, 192 {Ctrl_P, nv_up, NV_STS, FALSE}, 193 {Ctrl_Q, nv_visual, 0, FALSE}, 194 {Ctrl_R, nv_redo, 0, 0}, 195 {Ctrl_S, nv_ignore, 0, 0}, 196 {Ctrl_T, nv_tagpop, NV_NCW, 0}, 197 {Ctrl_U, nv_halfpage, 0, 0}, 198 {Ctrl_V, nv_visual, 0, FALSE}, 199 {'V', nv_visual, 0, FALSE}, 200 {'v', nv_visual, 0, FALSE}, 201 {Ctrl_W, nv_window, 0, 0}, 202 {Ctrl_X, nv_addsub, 0, 0}, 203 {Ctrl_Y, nv_scroll_line, 0, FALSE}, 204 {Ctrl_Z, nv_suspend, 0, 0}, 205 {ESC, nv_esc, 0, FALSE}, 206 {Ctrl_BSL, nv_normal, NV_NCH_ALW, 0}, 207 {Ctrl_RSB, nv_ident, NV_NCW, 0}, 208 {Ctrl_HAT, nv_hat, NV_NCW, 0}, 209 {Ctrl__, nv_error, 0, 0}, 210 {' ', nv_right, 0, 0}, 211 {'!', nv_operator, 0, 0}, 212 {'"', nv_regname, NV_NCH_NOP|NV_KEEPREG, 0}, 213 {'#', nv_ident, 0, 0}, 214 {'$', nv_dollar, 0, 0}, 215 {'%', nv_percent, 0, 0}, 216 {'&', nv_optrans, 0, 0}, 217 {'\'', nv_gomark, NV_NCH_ALW, TRUE}, 218 {'(', nv_brace, 0, BACKWARD}, 219 {')', nv_brace, 0, FORWARD}, 220 {'*', nv_ident, 0, 0}, 221 {'+', nv_down, 0, TRUE}, 222 {',', nv_csearch, 0, TRUE}, 223 {'-', nv_up, 0, TRUE}, 224 {'.', nv_dot, NV_KEEPREG, 0}, 225 {'/', nv_search, 0, FALSE}, 226 {'0', nv_beginline, 0, 0}, 227 {'1', nv_ignore, 0, 0}, 228 {'2', nv_ignore, 0, 0}, 229 {'3', nv_ignore, 0, 0}, 230 {'4', nv_ignore, 0, 0}, 231 {'5', nv_ignore, 0, 0}, 232 {'6', nv_ignore, 0, 0}, 233 {'7', nv_ignore, 0, 0}, 234 {'8', nv_ignore, 0, 0}, 235 {'9', nv_ignore, 0, 0}, 236 {':', nv_colon, 0, 0}, 237 {';', nv_csearch, 0, FALSE}, 238 {'<', nv_operator, NV_RL, 0}, 239 {'=', nv_operator, 0, 0}, 240 {'>', nv_operator, NV_RL, 0}, 241 {'?', nv_search, 0, FALSE}, 242 {'@', nv_at, NV_NCH_NOP, FALSE}, 243 {'A', nv_edit, 0, 0}, 244 {'B', nv_bck_word, 0, 1}, 245 {'C', nv_abbrev, NV_KEEPREG, 0}, 246 {'D', nv_abbrev, NV_KEEPREG, 0}, 247 {'E', nv_wordcmd, 0, TRUE}, 248 {'F', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD}, 249 {'G', nv_goto, 0, TRUE}, 250 {'H', nv_scroll, 0, 0}, 251 {'I', nv_edit, 0, 0}, 252 {'J', nv_join, 0, 0}, 253 {'K', nv_ident, 0, 0}, 254 {'L', nv_scroll, 0, 0}, 255 {'M', nv_scroll, 0, 0}, 256 {'N', nv_next, 0, SEARCH_REV}, 257 {'O', nv_open, 0, 0}, 258 {'P', nv_put, 0, 0}, 259 {'Q', nv_exmode, NV_NCW, 0}, 260 {'R', nv_Replace, 0, FALSE}, 261 {'S', nv_subst, NV_KEEPREG, 0}, 262 {'T', nv_csearch, NV_NCH_ALW|NV_LANG, BACKWARD}, 263 {'U', nv_Undo, 0, 0}, 264 {'W', nv_wordcmd, 0, TRUE}, 265 {'X', nv_abbrev, NV_KEEPREG, 0}, 266 {'Y', nv_abbrev, NV_KEEPREG, 0}, 267 {'Z', nv_Zet, NV_NCH_NOP|NV_NCW, 0}, 268 {'[', nv_brackets, NV_NCH_ALW, BACKWARD}, 269 {'\\', nv_error, 0, 0}, 270 {']', nv_brackets, NV_NCH_ALW, FORWARD}, 271 {'^', nv_beginline, 0, BL_WHITE | BL_FIX}, 272 {'_', nv_lineop, 0, 0}, 273 {'`', nv_gomark, NV_NCH_ALW, FALSE}, 274 {'a', nv_edit, NV_NCH, 0}, 275 {'b', nv_bck_word, 0, 0}, 276 {'c', nv_operator, 0, 0}, 277 {'d', nv_operator, 0, 0}, 278 {'e', nv_wordcmd, 0, FALSE}, 279 {'f', nv_csearch, NV_NCH_ALW|NV_LANG, FORWARD}, 280 {'g', nv_g_cmd, NV_NCH_ALW, FALSE}, 281 {'h', nv_left, NV_RL, 0}, 282 {'i', nv_edit, NV_NCH, 0}, 283 {'j', nv_down, 0, FALSE}, 284 {'k', nv_up, 0, FALSE}, 285 {'l', nv_right, NV_RL, 0}, 286 {'m', nv_mark, NV_NCH_NOP, 0}, 287 {'n', nv_next, 0, 0}, 288 {'o', nv_open, 0, 0}, 289 {'p', nv_put, 0, 0}, 290 {'q', nv_record, NV_NCH, 0}, 291 {'r', nv_replace, NV_NCH_NOP|NV_LANG, 0}, 292 {'s', nv_subst, NV_KEEPREG, 0}, 293 {'t', nv_csearch, NV_NCH_ALW|NV_LANG, FORWARD}, 294 {'u', nv_undo, 0, 0}, 295 {'w', nv_wordcmd, 0, FALSE}, 296 {'x', nv_abbrev, NV_KEEPREG, 0}, 297 {'y', nv_operator, 0, 0}, 298 {'z', nv_zet, NV_NCH_ALW, 0}, 299 {'{', nv_findpar, 0, BACKWARD}, 300 {'|', nv_pipe, 0, 0}, 301 {'}', nv_findpar, 0, FORWARD}, 302 {'~', nv_tilde, 0, 0}, 303 304 // pound sign 305 {POUND, nv_ident, 0, 0}, 306 {K_MOUSEUP, nv_mousescroll, 0, MSCR_UP}, 307 {K_MOUSEDOWN, nv_mousescroll, 0, MSCR_DOWN}, 308 {K_MOUSELEFT, nv_mousescroll, 0, MSCR_LEFT}, 309 {K_MOUSERIGHT, nv_mousescroll, 0, MSCR_RIGHT}, 310 {K_LEFTMOUSE, nv_mouse, 0, 0}, 311 {K_LEFTMOUSE_NM, nv_mouse, 0, 0}, 312 {K_LEFTDRAG, nv_mouse, 0, 0}, 313 {K_LEFTRELEASE, nv_mouse, 0, 0}, 314 {K_LEFTRELEASE_NM, nv_mouse, 0, 0}, 315 {K_MOUSEMOVE, nv_mouse, 0, 0}, 316 {K_MIDDLEMOUSE, nv_mouse, 0, 0}, 317 {K_MIDDLEDRAG, nv_mouse, 0, 0}, 318 {K_MIDDLERELEASE, nv_mouse, 0, 0}, 319 {K_RIGHTMOUSE, nv_mouse, 0, 0}, 320 {K_RIGHTDRAG, nv_mouse, 0, 0}, 321 {K_RIGHTRELEASE, nv_mouse, 0, 0}, 322 {K_X1MOUSE, nv_mouse, 0, 0}, 323 {K_X1DRAG, nv_mouse, 0, 0}, 324 {K_X1RELEASE, nv_mouse, 0, 0}, 325 {K_X2MOUSE, nv_mouse, 0, 0}, 326 {K_X2DRAG, nv_mouse, 0, 0}, 327 {K_X2RELEASE, nv_mouse, 0, 0}, 328 {K_IGNORE, nv_ignore, NV_KEEPREG, 0}, 329 {K_NOP, nv_nop, 0, 0}, 330 {K_INS, nv_edit, 0, 0}, 331 {K_KINS, nv_edit, 0, 0}, 332 {K_BS, nv_ctrlh, 0, 0}, 333 {K_UP, nv_up, NV_SSS|NV_STS, FALSE}, 334 {K_S_UP, nv_page, NV_SS, BACKWARD}, 335 {K_DOWN, nv_down, NV_SSS|NV_STS, FALSE}, 336 {K_S_DOWN, nv_page, NV_SS, FORWARD}, 337 {K_LEFT, nv_left, NV_SSS|NV_STS|NV_RL, 0}, 338 {K_S_LEFT, nv_bck_word, NV_SS|NV_RL, 0}, 339 {K_C_LEFT, nv_bck_word, NV_SSS|NV_RL|NV_STS, 1}, 340 {K_RIGHT, nv_right, NV_SSS|NV_STS|NV_RL, 0}, 341 {K_S_RIGHT, nv_wordcmd, NV_SS|NV_RL, FALSE}, 342 {K_C_RIGHT, nv_wordcmd, NV_SSS|NV_RL|NV_STS, TRUE}, 343 {K_PAGEUP, nv_page, NV_SSS|NV_STS, BACKWARD}, 344 {K_KPAGEUP, nv_page, NV_SSS|NV_STS, BACKWARD}, 345 {K_PAGEDOWN, nv_page, NV_SSS|NV_STS, FORWARD}, 346 {K_KPAGEDOWN, nv_page, NV_SSS|NV_STS, FORWARD}, 347 {K_END, nv_end, NV_SSS|NV_STS, FALSE}, 348 {K_KEND, nv_end, NV_SSS|NV_STS, FALSE}, 349 {K_S_END, nv_end, NV_SS, FALSE}, 350 {K_C_END, nv_end, NV_SSS|NV_STS, TRUE}, 351 {K_HOME, nv_home, NV_SSS|NV_STS, 0}, 352 {K_KHOME, nv_home, NV_SSS|NV_STS, 0}, 353 {K_S_HOME, nv_home, NV_SS, 0}, 354 {K_C_HOME, nv_goto, NV_SSS|NV_STS, FALSE}, 355 {K_DEL, nv_abbrev, 0, 0}, 356 {K_KDEL, nv_abbrev, 0, 0}, 357 {K_UNDO, nv_kundo, 0, 0}, 358 {K_HELP, nv_help, NV_NCW, 0}, 359 {K_F1, nv_help, NV_NCW, 0}, 360 {K_XF1, nv_help, NV_NCW, 0}, 361 {K_SELECT, nv_select, 0, 0}, 362 #ifdef FEAT_GUI 363 {K_VER_SCROLLBAR, nv_ver_scrollbar, 0, 0}, 364 {K_HOR_SCROLLBAR, nv_hor_scrollbar, 0, 0}, 365 #endif 366 #ifdef FEAT_GUI_TABLINE 367 {K_TABLINE, nv_tabline, 0, 0}, 368 {K_TABMENU, nv_tabmenu, 0, 0}, 369 #endif 370 #ifdef FEAT_NETBEANS_INTG 371 {K_F21, nv_nbcmd, NV_NCH_ALW, 0}, 372 #endif 373 #ifdef FEAT_DND 374 {K_DROP, nv_drop, NV_STS, 0}, 375 #endif 376 {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0}, 377 {K_PS, nv_edit, 0, 0}, 378 }; 379 380 // Number of commands in nv_cmds[]. 381 #define NV_CMDS_SIZE (sizeof(nv_cmds) / sizeof(struct nv_cmd)) 382 383 // Sorted index of commands in nv_cmds[]. 384 static short nv_cmd_idx[NV_CMDS_SIZE]; 385 386 // The highest index for which 387 // nv_cmds[idx].cmd_char == nv_cmd_idx[nv_cmds[idx].cmd_char] 388 static int nv_max_linear; 389 390 /* 391 * Compare functions for qsort() below, that checks the command character 392 * through the index in nv_cmd_idx[]. 393 */ 394 static int 395 nv_compare(const void *s1, const void *s2) 396 { 397 int c1, c2; 398 399 // The commands are sorted on absolute value. 400 c1 = nv_cmds[*(const short *)s1].cmd_char; 401 c2 = nv_cmds[*(const short *)s2].cmd_char; 402 if (c1 < 0) 403 c1 = -c1; 404 if (c2 < 0) 405 c2 = -c2; 406 return c1 - c2; 407 } 408 409 /* 410 * Initialize the nv_cmd_idx[] table. 411 */ 412 void 413 init_normal_cmds(void) 414 { 415 int i; 416 417 // Fill the index table with a one to one relation. 418 for (i = 0; i < (int)NV_CMDS_SIZE; ++i) 419 nv_cmd_idx[i] = i; 420 421 // Sort the commands by the command character. 422 qsort((void *)&nv_cmd_idx, (size_t)NV_CMDS_SIZE, sizeof(short), nv_compare); 423 424 // Find the first entry that can't be indexed by the command character. 425 for (i = 0; i < (int)NV_CMDS_SIZE; ++i) 426 if (i != nv_cmds[nv_cmd_idx[i]].cmd_char) 427 break; 428 nv_max_linear = i - 1; 429 } 430 431 /* 432 * Search for a command in the commands table. 433 * Returns -1 for invalid command. 434 */ 435 static int 436 find_command(int cmdchar) 437 { 438 int i; 439 int idx; 440 int top, bot; 441 int c; 442 443 // A multi-byte character is never a command. 444 if (cmdchar >= 0x100) 445 return -1; 446 447 // We use the absolute value of the character. Special keys have a 448 // negative value, but are sorted on their absolute value. 449 if (cmdchar < 0) 450 cmdchar = -cmdchar; 451 452 // If the character is in the first part: The character is the index into 453 // nv_cmd_idx[]. 454 if (cmdchar <= nv_max_linear) 455 return nv_cmd_idx[cmdchar]; 456 457 // Perform a binary search. 458 bot = nv_max_linear + 1; 459 top = NV_CMDS_SIZE - 1; 460 idx = -1; 461 while (bot <= top) 462 { 463 i = (top + bot) / 2; 464 c = nv_cmds[nv_cmd_idx[i]].cmd_char; 465 if (c < 0) 466 c = -c; 467 if (cmdchar == c) 468 { 469 idx = nv_cmd_idx[i]; 470 break; 471 } 472 if (cmdchar > c) 473 bot = i + 1; 474 else 475 top = i - 1; 476 } 477 return idx; 478 } 479 480 /* 481 * Execute a command in Normal mode. 482 */ 483 void 484 normal_cmd( 485 oparg_T *oap, 486 int toplevel UNUSED) // TRUE when called from main() 487 { 488 cmdarg_T ca; // command arguments 489 int c; 490 int ctrl_w = FALSE; // got CTRL-W command 491 int old_col = curwin->w_curswant; 492 #ifdef FEAT_CMDL_INFO 493 int need_flushbuf; // need to call out_flush() 494 #endif 495 pos_T old_pos; // cursor position before command 496 int mapped_len; 497 static int old_mapped_len = 0; 498 int idx; 499 #ifdef FEAT_EVAL 500 int set_prevcount = FALSE; 501 #endif 502 int save_did_cursorhold = did_cursorhold; 503 504 CLEAR_FIELD(ca); // also resets ca.retval 505 ca.oap = oap; 506 507 // Use a count remembered from before entering an operator. After typing 508 // "3d" we return from normal_cmd() and come back here, the "3" is 509 // remembered in "opcount". 510 ca.opcount = opcount; 511 512 /* 513 * If there is an operator pending, then the command we take this time 514 * will terminate it. Finish_op tells us to finish the operation before 515 * returning this time (unless the operation was cancelled). 516 */ 517 #ifdef CURSOR_SHAPE 518 c = finish_op; 519 #endif 520 finish_op = (oap->op_type != OP_NOP); 521 #ifdef CURSOR_SHAPE 522 if (finish_op != c) 523 { 524 ui_cursor_shape(); // may show different cursor shape 525 # ifdef FEAT_MOUSESHAPE 526 update_mouseshape(-1); 527 # endif 528 } 529 #endif 530 531 // When not finishing an operator and no register name typed, reset the 532 // count. 533 if (!finish_op && !oap->regname) 534 { 535 ca.opcount = 0; 536 #ifdef FEAT_EVAL 537 set_prevcount = TRUE; 538 #endif 539 } 540 541 // Restore counts from before receiving K_CURSORHOLD. This means after 542 // typing "3", handling K_CURSORHOLD and then typing "2" we get "32", not 543 // "3 * 2". 544 if (oap->prev_opcount > 0 || oap->prev_count0 > 0) 545 { 546 ca.opcount = oap->prev_opcount; 547 ca.count0 = oap->prev_count0; 548 oap->prev_opcount = 0; 549 oap->prev_count0 = 0; 550 } 551 552 mapped_len = typebuf_maplen(); 553 554 State = NORMAL_BUSY; 555 #ifdef USE_ON_FLY_SCROLL 556 dont_scroll = FALSE; // allow scrolling here 557 #endif 558 559 #ifdef FEAT_EVAL 560 // Set v:count here, when called from main() and not a stuffed 561 // command, so that v:count can be used in an expression mapping 562 // when there is no count. Do set it for redo. 563 if (toplevel && readbuf1_empty()) 564 set_vcount_ca(&ca, &set_prevcount); 565 #endif 566 567 /* 568 * Get the command character from the user. 569 */ 570 c = safe_vgetc(); 571 LANGMAP_ADJUST(c, get_real_state() != SELECTMODE); 572 573 /* 574 * If a mapping was started in Visual or Select mode, remember the length 575 * of the mapping. This is used below to not return to Insert mode for as 576 * long as the mapping is being executed. 577 */ 578 if (restart_edit == 0) 579 old_mapped_len = 0; 580 else if (old_mapped_len 581 || (VIsual_active && mapped_len == 0 && typebuf_maplen() > 0)) 582 old_mapped_len = typebuf_maplen(); 583 584 if (c == NUL) 585 c = K_ZERO; 586 587 /* 588 * In Select mode, typed text replaces the selection. 589 */ 590 if (VIsual_active 591 && VIsual_select 592 && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER)) 593 { 594 // Fake a "c"hange command. When "restart_edit" is set (e.g., because 595 // 'insertmode' is set) fake a "d"elete command, Insert mode will 596 // restart automatically. 597 // Insert the typed character in the typeahead buffer, so that it can 598 // be mapped in Insert mode. Required for ":lmap" to work. 599 ins_char_typebuf(vgetc_char, vgetc_mod_mask); 600 if (restart_edit != 0) 601 c = 'd'; 602 else 603 c = 'c'; 604 msg_nowait = TRUE; // don't delay going to insert mode 605 old_mapped_len = 0; // do go to Insert mode 606 } 607 608 #ifdef FEAT_CMDL_INFO 609 need_flushbuf = add_to_showcmd(c); 610 #endif 611 612 getcount: 613 if (!(VIsual_active && VIsual_select)) 614 { 615 /* 616 * Handle a count before a command and compute ca.count0. 617 * Note that '0' is a command and not the start of a count, but it's 618 * part of a count after other digits. 619 */ 620 while ( (c >= '1' && c <= '9') 621 || (ca.count0 != 0 && (c == K_DEL || c == K_KDEL || c == '0'))) 622 { 623 if (c == K_DEL || c == K_KDEL) 624 { 625 ca.count0 /= 10; 626 #ifdef FEAT_CMDL_INFO 627 del_from_showcmd(4); // delete the digit and ~@% 628 #endif 629 } 630 else 631 ca.count0 = ca.count0 * 10 + (c - '0'); 632 if (ca.count0 < 0) // got too large! 633 ca.count0 = 999999999L; 634 #ifdef FEAT_EVAL 635 // Set v:count here, when called from main() and not a stuffed 636 // command, so that v:count can be used in an expression mapping 637 // right after the count. Do set it for redo. 638 if (toplevel && readbuf1_empty()) 639 set_vcount_ca(&ca, &set_prevcount); 640 #endif 641 if (ctrl_w) 642 { 643 ++no_mapping; 644 ++allow_keys; // no mapping for nchar, but keys 645 } 646 ++no_zero_mapping; // don't map zero here 647 c = plain_vgetc(); 648 LANGMAP_ADJUST(c, TRUE); 649 --no_zero_mapping; 650 if (ctrl_w) 651 { 652 --no_mapping; 653 --allow_keys; 654 } 655 #ifdef FEAT_CMDL_INFO 656 need_flushbuf |= add_to_showcmd(c); 657 #endif 658 } 659 660 /* 661 * If we got CTRL-W there may be a/another count 662 */ 663 if (c == Ctrl_W && !ctrl_w && oap->op_type == OP_NOP) 664 { 665 ctrl_w = TRUE; 666 ca.opcount = ca.count0; // remember first count 667 ca.count0 = 0; 668 ++no_mapping; 669 ++allow_keys; // no mapping for nchar, but keys 670 c = plain_vgetc(); // get next character 671 LANGMAP_ADJUST(c, TRUE); 672 --no_mapping; 673 --allow_keys; 674 #ifdef FEAT_CMDL_INFO 675 need_flushbuf |= add_to_showcmd(c); 676 #endif 677 goto getcount; // jump back 678 } 679 } 680 681 if (c == K_CURSORHOLD) 682 { 683 // Save the count values so that ca.opcount and ca.count0 are exactly 684 // the same when coming back here after handling K_CURSORHOLD. 685 oap->prev_opcount = ca.opcount; 686 oap->prev_count0 = ca.count0; 687 } 688 else if (ca.opcount != 0) 689 { 690 /* 691 * If we're in the middle of an operator (including after entering a 692 * yank buffer with '"') AND we had a count before the operator, then 693 * that count overrides the current value of ca.count0. 694 * What this means effectively, is that commands like "3dw" get turned 695 * into "d3w" which makes things fall into place pretty neatly. 696 * If you give a count before AND after the operator, they are 697 * multiplied. 698 */ 699 if (ca.count0) 700 ca.count0 *= ca.opcount; 701 else 702 ca.count0 = ca.opcount; 703 } 704 705 /* 706 * Always remember the count. It will be set to zero (on the next call, 707 * above) when there is no pending operator. 708 * When called from main(), save the count for use by the "count" built-in 709 * variable. 710 */ 711 ca.opcount = ca.count0; 712 ca.count1 = (ca.count0 == 0 ? 1 : ca.count0); 713 714 #ifdef FEAT_EVAL 715 /* 716 * Only set v:count when called from main() and not a stuffed command. 717 * Do set it for redo. 718 */ 719 if (toplevel && readbuf1_empty()) 720 set_vcount(ca.count0, ca.count1, set_prevcount); 721 #endif 722 723 /* 724 * Find the command character in the table of commands. 725 * For CTRL-W we already got nchar when looking for a count. 726 */ 727 if (ctrl_w) 728 { 729 ca.nchar = c; 730 ca.cmdchar = Ctrl_W; 731 } 732 else 733 ca.cmdchar = c; 734 idx = find_command(ca.cmdchar); 735 if (idx < 0) 736 { 737 // Not a known command: beep. 738 clearopbeep(oap); 739 goto normal_end; 740 } 741 742 if (text_locked() && (nv_cmds[idx].cmd_flags & NV_NCW)) 743 { 744 // This command is not allowed while editing a cmdline: beep. 745 clearopbeep(oap); 746 text_locked_msg(); 747 goto normal_end; 748 } 749 if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked()) 750 goto normal_end; 751 752 /* 753 * In Visual/Select mode, a few keys are handled in a special way. 754 */ 755 if (VIsual_active) 756 { 757 // when 'keymodel' contains "stopsel" may stop Select/Visual mode 758 if (km_stopsel 759 && (nv_cmds[idx].cmd_flags & NV_STS) 760 && !(mod_mask & MOD_MASK_SHIFT)) 761 { 762 end_visual_mode(); 763 redraw_curbuf_later(INVERTED); 764 } 765 766 // Keys that work different when 'keymodel' contains "startsel" 767 if (km_startsel) 768 { 769 if (nv_cmds[idx].cmd_flags & NV_SS) 770 { 771 unshift_special(&ca); 772 idx = find_command(ca.cmdchar); 773 if (idx < 0) 774 { 775 // Just in case 776 clearopbeep(oap); 777 goto normal_end; 778 } 779 } 780 else if ((nv_cmds[idx].cmd_flags & NV_SSS) 781 && (mod_mask & MOD_MASK_SHIFT)) 782 mod_mask &= ~MOD_MASK_SHIFT; 783 } 784 } 785 786 #ifdef FEAT_RIGHTLEFT 787 if (curwin->w_p_rl && KeyTyped && !KeyStuffed 788 && (nv_cmds[idx].cmd_flags & NV_RL)) 789 { 790 // Invert horizontal movements and operations. Only when typed by the 791 // user directly, not when the result of a mapping or "x" translated 792 // to "dl". 793 switch (ca.cmdchar) 794 { 795 case 'l': ca.cmdchar = 'h'; break; 796 case K_RIGHT: ca.cmdchar = K_LEFT; break; 797 case K_S_RIGHT: ca.cmdchar = K_S_LEFT; break; 798 case K_C_RIGHT: ca.cmdchar = K_C_LEFT; break; 799 case 'h': ca.cmdchar = 'l'; break; 800 case K_LEFT: ca.cmdchar = K_RIGHT; break; 801 case K_S_LEFT: ca.cmdchar = K_S_RIGHT; break; 802 case K_C_LEFT: ca.cmdchar = K_C_RIGHT; break; 803 case '>': ca.cmdchar = '<'; break; 804 case '<': ca.cmdchar = '>'; break; 805 } 806 idx = find_command(ca.cmdchar); 807 } 808 #endif 809 810 /* 811 * Get an additional character if we need one. 812 */ 813 if ((nv_cmds[idx].cmd_flags & NV_NCH) 814 && (((nv_cmds[idx].cmd_flags & NV_NCH_NOP) == NV_NCH_NOP 815 && oap->op_type == OP_NOP) 816 || (nv_cmds[idx].cmd_flags & NV_NCH_ALW) == NV_NCH_ALW 817 || (ca.cmdchar == 'q' 818 && oap->op_type == OP_NOP 819 && reg_recording == 0 820 && reg_executing == 0) 821 || ((ca.cmdchar == 'a' || ca.cmdchar == 'i') 822 && (oap->op_type != OP_NOP || VIsual_active)))) 823 { 824 int *cp; 825 int repl = FALSE; // get character for replace mode 826 int lit = FALSE; // get extra character literally 827 int langmap_active = FALSE; // using :lmap mappings 828 int lang; // getting a text character 829 #ifdef HAVE_INPUT_METHOD 830 int save_smd; // saved value of p_smd 831 #endif 832 833 ++no_mapping; 834 ++allow_keys; // no mapping for nchar, but allow key codes 835 // Don't generate a CursorHold event here, most commands can't handle 836 // it, e.g., nv_replace(), nv_csearch(). 837 did_cursorhold = TRUE; 838 if (ca.cmdchar == 'g') 839 { 840 /* 841 * For 'g' get the next character now, so that we can check for 842 * "gr", "g'" and "g`". 843 */ 844 ca.nchar = plain_vgetc(); 845 LANGMAP_ADJUST(ca.nchar, TRUE); 846 #ifdef FEAT_CMDL_INFO 847 need_flushbuf |= add_to_showcmd(ca.nchar); 848 #endif 849 if (ca.nchar == 'r' || ca.nchar == '\'' || ca.nchar == '`' 850 || ca.nchar == Ctrl_BSL) 851 { 852 cp = &ca.extra_char; // need to get a third character 853 if (ca.nchar != 'r') 854 lit = TRUE; // get it literally 855 else 856 repl = TRUE; // get it in replace mode 857 } 858 else 859 cp = NULL; // no third character needed 860 } 861 else 862 { 863 if (ca.cmdchar == 'r') // get it in replace mode 864 repl = TRUE; 865 cp = &ca.nchar; 866 } 867 lang = (repl || (nv_cmds[idx].cmd_flags & NV_LANG)); 868 869 /* 870 * Get a second or third character. 871 */ 872 if (cp != NULL) 873 { 874 if (repl) 875 { 876 State = REPLACE; // pretend Replace mode 877 #ifdef CURSOR_SHAPE 878 ui_cursor_shape(); // show different cursor shape 879 #endif 880 } 881 if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) 882 { 883 // Allow mappings defined with ":lmap". 884 --no_mapping; 885 --allow_keys; 886 if (repl) 887 State = LREPLACE; 888 else 889 State = LANGMAP; 890 langmap_active = TRUE; 891 } 892 #ifdef HAVE_INPUT_METHOD 893 save_smd = p_smd; 894 p_smd = FALSE; // Don't let the IM code show the mode here 895 if (lang && curbuf->b_p_iminsert == B_IMODE_IM) 896 im_set_active(TRUE); 897 #endif 898 899 *cp = plain_vgetc(); 900 901 if (langmap_active) 902 { 903 // Undo the decrement done above 904 ++no_mapping; 905 ++allow_keys; 906 State = NORMAL_BUSY; 907 } 908 #ifdef HAVE_INPUT_METHOD 909 if (lang) 910 { 911 if (curbuf->b_p_iminsert != B_IMODE_LMAP) 912 im_save_status(&curbuf->b_p_iminsert); 913 im_set_active(FALSE); 914 } 915 p_smd = save_smd; 916 #endif 917 State = NORMAL_BUSY; 918 #ifdef FEAT_CMDL_INFO 919 need_flushbuf |= add_to_showcmd(*cp); 920 #endif 921 922 if (!lit) 923 { 924 #ifdef FEAT_DIGRAPHS 925 // Typing CTRL-K gets a digraph. 926 if (*cp == Ctrl_K 927 && ((nv_cmds[idx].cmd_flags & NV_LANG) 928 || cp == &ca.extra_char) 929 && vim_strchr(p_cpo, CPO_DIGRAPH) == NULL) 930 { 931 c = get_digraph(FALSE); 932 if (c > 0) 933 { 934 *cp = c; 935 # ifdef FEAT_CMDL_INFO 936 // Guessing how to update showcmd here... 937 del_from_showcmd(3); 938 need_flushbuf |= add_to_showcmd(*cp); 939 # endif 940 } 941 } 942 #endif 943 944 // adjust chars > 127, except after "tTfFr" commands 945 LANGMAP_ADJUST(*cp, !lang); 946 #ifdef FEAT_RIGHTLEFT 947 // adjust Hebrew mapped char 948 if (p_hkmap && lang && KeyTyped) 949 *cp = hkmap(*cp); 950 #endif 951 } 952 953 /* 954 * When the next character is CTRL-\ a following CTRL-N means the 955 * command is aborted and we go to Normal mode. 956 */ 957 if (cp == &ca.extra_char 958 && ca.nchar == Ctrl_BSL 959 && (ca.extra_char == Ctrl_N || ca.extra_char == Ctrl_G)) 960 { 961 ca.cmdchar = Ctrl_BSL; 962 ca.nchar = ca.extra_char; 963 idx = find_command(ca.cmdchar); 964 } 965 else if ((ca.nchar == 'n' || ca.nchar == 'N') && ca.cmdchar == 'g') 966 ca.oap->op_type = get_op_type(*cp, NUL); 967 else if (*cp == Ctrl_BSL) 968 { 969 long towait = (p_ttm >= 0 ? p_ttm : p_tm); 970 971 // There is a busy wait here when typing "f<C-\>" and then 972 // something different from CTRL-N. Can't be avoided. 973 while ((c = vpeekc()) <= 0 && towait > 0L) 974 { 975 do_sleep(towait > 50L ? 50L : towait); 976 towait -= 50L; 977 } 978 if (c > 0) 979 { 980 c = plain_vgetc(); 981 if (c != Ctrl_N && c != Ctrl_G) 982 vungetc(c); 983 else 984 { 985 ca.cmdchar = Ctrl_BSL; 986 ca.nchar = c; 987 idx = find_command(ca.cmdchar); 988 } 989 } 990 } 991 992 // When getting a text character and the next character is a 993 // multi-byte character, it could be a composing character. 994 // However, don't wait for it to arrive. Also, do enable mapping, 995 // because if it's put back with vungetc() it's too late to apply 996 // mapping. 997 --no_mapping; 998 while (enc_utf8 && lang && (c = vpeekc()) > 0 999 && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) 1000 { 1001 c = plain_vgetc(); 1002 if (!utf_iscomposing(c)) 1003 { 1004 vungetc(c); // it wasn't, put it back 1005 break; 1006 } 1007 else if (ca.ncharC1 == 0) 1008 ca.ncharC1 = c; 1009 else 1010 ca.ncharC2 = c; 1011 } 1012 ++no_mapping; 1013 } 1014 --no_mapping; 1015 --allow_keys; 1016 } 1017 1018 #ifdef FEAT_CMDL_INFO 1019 /* 1020 * Flush the showcmd characters onto the screen so we can see them while 1021 * the command is being executed. Only do this when the shown command was 1022 * actually displayed, otherwise this will slow down a lot when executing 1023 * mappings. 1024 */ 1025 if (need_flushbuf) 1026 out_flush(); 1027 #endif 1028 if (ca.cmdchar != K_IGNORE) 1029 { 1030 if (ex_normal_busy) 1031 did_cursorhold = save_did_cursorhold; 1032 else 1033 did_cursorhold = FALSE; 1034 } 1035 1036 State = NORMAL; 1037 1038 if (ca.nchar == ESC) 1039 { 1040 clearop(oap); 1041 if (restart_edit == 0 && goto_im()) 1042 restart_edit = 'a'; 1043 goto normal_end; 1044 } 1045 1046 if (ca.cmdchar != K_IGNORE) 1047 { 1048 msg_didout = FALSE; // don't scroll screen up for normal command 1049 msg_col = 0; 1050 } 1051 1052 old_pos = curwin->w_cursor; // remember where cursor was 1053 1054 // When 'keymodel' contains "startsel" some keys start Select/Visual 1055 // mode. 1056 if (!VIsual_active && km_startsel) 1057 { 1058 if (nv_cmds[idx].cmd_flags & NV_SS) 1059 { 1060 start_selection(); 1061 unshift_special(&ca); 1062 idx = find_command(ca.cmdchar); 1063 } 1064 else if ((nv_cmds[idx].cmd_flags & NV_SSS) 1065 && (mod_mask & MOD_MASK_SHIFT)) 1066 { 1067 start_selection(); 1068 mod_mask &= ~MOD_MASK_SHIFT; 1069 } 1070 } 1071 1072 /* 1073 * Execute the command! 1074 * Call the command function found in the commands table. 1075 */ 1076 ca.arg = nv_cmds[idx].cmd_arg; 1077 (nv_cmds[idx].cmd_func)(&ca); 1078 1079 /* 1080 * If we didn't start or finish an operator, reset oap->regname, unless we 1081 * need it later. 1082 */ 1083 if (!finish_op 1084 && !oap->op_type 1085 && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG))) 1086 { 1087 clearop(oap); 1088 #ifdef FEAT_EVAL 1089 reset_reg_var(); 1090 #endif 1091 } 1092 1093 // Get the length of mapped chars again after typing a count, second 1094 // character or "z333<cr>". 1095 if (old_mapped_len > 0) 1096 old_mapped_len = typebuf_maplen(); 1097 1098 /* 1099 * If an operation is pending, handle it. But not for K_IGNORE. 1100 */ 1101 if (ca.cmdchar != K_IGNORE) 1102 do_pending_operator(&ca, old_col, FALSE); 1103 1104 /* 1105 * Wait for a moment when a message is displayed that will be overwritten 1106 * by the mode message. 1107 * In Visual mode and with "^O" in Insert mode, a short message will be 1108 * overwritten by the mode message. Wait a bit, until a key is hit. 1109 * In Visual mode, it's more important to keep the Visual area updated 1110 * than keeping a message (e.g. from a /pat search). 1111 * Only do this if the command was typed, not from a mapping. 1112 * Don't wait when emsg_silent is non-zero. 1113 * Also wait a bit after an error message, e.g. for "^O:". 1114 * Don't redraw the screen, it would remove the message. 1115 */ 1116 if ( ((p_smd 1117 && msg_silent == 0 1118 && (restart_edit != 0 1119 || (VIsual_active 1120 && old_pos.lnum == curwin->w_cursor.lnum 1121 && old_pos.col == curwin->w_cursor.col) 1122 ) 1123 && (clear_cmdline 1124 || redraw_cmdline) 1125 && (msg_didout || (msg_didany && msg_scroll)) 1126 && !msg_nowait 1127 && KeyTyped) 1128 || (restart_edit != 0 1129 && !VIsual_active 1130 && (msg_scroll 1131 || emsg_on_display))) 1132 && oap->regname == 0 1133 && !(ca.retval & CA_COMMAND_BUSY) 1134 && stuff_empty() 1135 && typebuf_typed() 1136 && emsg_silent == 0 1137 && !did_wait_return 1138 && oap->op_type == OP_NOP) 1139 { 1140 int save_State = State; 1141 1142 // Draw the cursor with the right shape here 1143 if (restart_edit != 0) 1144 State = INSERT; 1145 1146 // If need to redraw, and there is a "keep_msg", redraw before the 1147 // delay 1148 if (must_redraw && keep_msg != NULL && !emsg_on_display) 1149 { 1150 char_u *kmsg; 1151 1152 kmsg = keep_msg; 1153 keep_msg = NULL; 1154 // Showmode() will clear keep_msg, but we want to use it anyway. 1155 // First update w_topline. 1156 setcursor(); 1157 update_screen(0); 1158 // now reset it, otherwise it's put in the history again 1159 keep_msg = kmsg; 1160 1161 kmsg = vim_strsave(keep_msg); 1162 if (kmsg != NULL) 1163 { 1164 msg_attr((char *)kmsg, keep_msg_attr); 1165 vim_free(kmsg); 1166 } 1167 } 1168 setcursor(); 1169 #ifdef CURSOR_SHAPE 1170 ui_cursor_shape(); // may show different cursor shape 1171 #endif 1172 cursor_on(); 1173 out_flush(); 1174 if (msg_scroll || emsg_on_display) 1175 ui_delay(1003L, TRUE); // wait at least one second 1176 ui_delay(3003L, FALSE); // wait up to three seconds 1177 State = save_State; 1178 1179 msg_scroll = FALSE; 1180 emsg_on_display = FALSE; 1181 } 1182 1183 /* 1184 * Finish up after executing a Normal mode command. 1185 */ 1186 normal_end: 1187 1188 msg_nowait = FALSE; 1189 1190 #ifdef FEAT_EVAL 1191 if (finish_op) 1192 reset_reg_var(); 1193 #endif 1194 1195 // Reset finish_op, in case it was set 1196 #ifdef CURSOR_SHAPE 1197 c = finish_op; 1198 #endif 1199 finish_op = FALSE; 1200 #ifdef CURSOR_SHAPE 1201 // Redraw the cursor with another shape, if we were in Operator-pending 1202 // mode or did a replace command. 1203 if (c || ca.cmdchar == 'r') 1204 { 1205 ui_cursor_shape(); // may show different cursor shape 1206 # ifdef FEAT_MOUSESHAPE 1207 update_mouseshape(-1); 1208 # endif 1209 } 1210 #endif 1211 1212 #ifdef FEAT_CMDL_INFO 1213 if (oap->op_type == OP_NOP && oap->regname == 0 1214 && ca.cmdchar != K_CURSORHOLD) 1215 clear_showcmd(); 1216 #endif 1217 1218 checkpcmark(); // check if we moved since setting pcmark 1219 vim_free(ca.searchbuf); 1220 1221 if (has_mbyte) 1222 mb_adjust_cursor(); 1223 1224 if (curwin->w_p_scb && toplevel) 1225 { 1226 validate_cursor(); // may need to update w_leftcol 1227 do_check_scrollbind(TRUE); 1228 } 1229 1230 if (curwin->w_p_crb && toplevel) 1231 { 1232 validate_cursor(); // may need to update w_leftcol 1233 do_check_cursorbind(); 1234 } 1235 1236 #ifdef FEAT_TERMINAL 1237 // don't go to Insert mode if a terminal has a running job 1238 if (term_job_running(curbuf->b_term)) 1239 restart_edit = 0; 1240 #endif 1241 1242 /* 1243 * May restart edit(), if we got here with CTRL-O in Insert mode (but not 1244 * if still inside a mapping that started in Visual mode). 1245 * May switch from Visual to Select mode after CTRL-O command. 1246 */ 1247 if ( oap->op_type == OP_NOP 1248 && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0) 1249 || restart_VIsual_select == 1) 1250 && !(ca.retval & CA_COMMAND_BUSY) 1251 && stuff_empty() 1252 && oap->regname == 0) 1253 { 1254 if (restart_VIsual_select == 1) 1255 { 1256 VIsual_select = TRUE; 1257 showmode(); 1258 restart_VIsual_select = 0; 1259 } 1260 if (restart_edit != 0 && !VIsual_active && old_mapped_len == 0) 1261 (void)edit(restart_edit, FALSE, 1L); 1262 } 1263 1264 if (restart_VIsual_select == 2) 1265 restart_VIsual_select = 1; 1266 1267 // Save count before an operator for next time. 1268 opcount = ca.opcount; 1269 } 1270 1271 #ifdef FEAT_EVAL 1272 /* 1273 * Set v:count and v:count1 according to "cap". 1274 * Set v:prevcount only when "set_prevcount" is TRUE. 1275 */ 1276 static void 1277 set_vcount_ca(cmdarg_T *cap, int *set_prevcount) 1278 { 1279 long count = cap->count0; 1280 1281 // multiply with cap->opcount the same way as above 1282 if (cap->opcount != 0) 1283 count = cap->opcount * (count == 0 ? 1 : count); 1284 set_vcount(count, count == 0 ? 1 : count, *set_prevcount); 1285 *set_prevcount = FALSE; // only set v:prevcount once 1286 } 1287 #endif 1288 1289 /* 1290 * Check if highlighting for Visual mode is possible, give a warning message 1291 * if not. 1292 */ 1293 void 1294 check_visual_highlight(void) 1295 { 1296 static int did_check = FALSE; 1297 1298 if (full_screen) 1299 { 1300 if (!did_check && HL_ATTR(HLF_V) == 0) 1301 msg(_("Warning: terminal cannot highlight")); 1302 did_check = TRUE; 1303 } 1304 } 1305 1306 /* 1307 * End Visual mode. 1308 * This function should ALWAYS be called to end Visual mode, except from 1309 * do_pending_operator(). 1310 */ 1311 void 1312 end_visual_mode(void) 1313 { 1314 #ifdef FEAT_CLIPBOARD 1315 /* 1316 * If we are using the clipboard, then remember what was selected in case 1317 * we need to paste it somewhere while we still own the selection. 1318 * Only do this when the clipboard is already owned. Don't want to grab 1319 * the selection when hitting ESC. 1320 */ 1321 if (clip_star.available && clip_star.owned) 1322 clip_auto_select(); 1323 #endif 1324 1325 VIsual_active = FALSE; 1326 setmouse(); 1327 mouse_dragging = 0; 1328 1329 // Save the current VIsual area for '< and '> marks, and "gv" 1330 curbuf->b_visual.vi_mode = VIsual_mode; 1331 curbuf->b_visual.vi_start = VIsual; 1332 curbuf->b_visual.vi_end = curwin->w_cursor; 1333 curbuf->b_visual.vi_curswant = curwin->w_curswant; 1334 #ifdef FEAT_EVAL 1335 curbuf->b_visual_mode_eval = VIsual_mode; 1336 #endif 1337 if (!virtual_active()) 1338 curwin->w_cursor.coladd = 0; 1339 may_clear_cmdline(); 1340 1341 adjust_cursor_eol(); 1342 } 1343 1344 /* 1345 * Reset VIsual_active and VIsual_reselect. 1346 */ 1347 void 1348 reset_VIsual_and_resel(void) 1349 { 1350 if (VIsual_active) 1351 { 1352 end_visual_mode(); 1353 redraw_curbuf_later(INVERTED); // delete the inversion later 1354 } 1355 VIsual_reselect = FALSE; 1356 } 1357 1358 /* 1359 * Reset VIsual_active and VIsual_reselect if it's set. 1360 */ 1361 void 1362 reset_VIsual(void) 1363 { 1364 if (VIsual_active) 1365 { 1366 end_visual_mode(); 1367 redraw_curbuf_later(INVERTED); // delete the inversion later 1368 VIsual_reselect = FALSE; 1369 } 1370 } 1371 1372 void 1373 restore_visual_mode(void) 1374 { 1375 if (VIsual_mode_orig != NUL) 1376 { 1377 curbuf->b_visual.vi_mode = VIsual_mode_orig; 1378 VIsual_mode_orig = NUL; 1379 } 1380 } 1381 1382 /* 1383 * Check for a balloon-eval special item to include when searching for an 1384 * identifier. When "dir" is BACKWARD "ptr[-1]" must be valid! 1385 * Returns TRUE if the character at "*ptr" should be included. 1386 * "dir" is FORWARD or BACKWARD, the direction of searching. 1387 * "*colp" is in/decremented if "ptr[-dir]" should also be included. 1388 * "bnp" points to a counter for square brackets. 1389 */ 1390 static int 1391 find_is_eval_item( 1392 char_u *ptr, 1393 int *colp, 1394 int *bnp, 1395 int dir) 1396 { 1397 // Accept everything inside []. 1398 if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD)) 1399 ++*bnp; 1400 if (*bnp > 0) 1401 { 1402 if ((*ptr == '[' && dir == BACKWARD) || (*ptr == ']' && dir == FORWARD)) 1403 --*bnp; 1404 return TRUE; 1405 } 1406 1407 // skip over "s.var" 1408 if (*ptr == '.') 1409 return TRUE; 1410 1411 // two-character item: s->var 1412 if (ptr[dir == BACKWARD ? 0 : 1] == '>' 1413 && ptr[dir == BACKWARD ? -1 : 0] == '-') 1414 { 1415 *colp += dir; 1416 return TRUE; 1417 } 1418 return FALSE; 1419 } 1420 1421 /* 1422 * Find the identifier under or to the right of the cursor. 1423 * "find_type" can have one of three values: 1424 * FIND_IDENT: find an identifier (keyword) 1425 * FIND_STRING: find any non-white text 1426 * FIND_IDENT + FIND_STRING: find any non-white text, identifier preferred. 1427 * FIND_EVAL: find text useful for C program debugging 1428 * 1429 * There are three steps: 1430 * 1. Search forward for the start of an identifier/text. Doesn't move if 1431 * already on one. 1432 * 2. Search backward for the start of this identifier/text. 1433 * This doesn't match the real Vi but I like it a little better and it 1434 * shouldn't bother anyone. 1435 * 3. Search forward to the end of this identifier/text. 1436 * When FIND_IDENT isn't defined, we backup until a blank. 1437 * 1438 * Returns the length of the text, or zero if no text is found. 1439 * If text is found, a pointer to the text is put in "*text". This 1440 * points into the current buffer line and is not always NUL terminated. 1441 */ 1442 int 1443 find_ident_under_cursor(char_u **text, int find_type) 1444 { 1445 return find_ident_at_pos(curwin, curwin->w_cursor.lnum, 1446 curwin->w_cursor.col, text, NULL, find_type); 1447 } 1448 1449 /* 1450 * Like find_ident_under_cursor(), but for any window and any position. 1451 * However: Uses 'iskeyword' from the current window!. 1452 */ 1453 int 1454 find_ident_at_pos( 1455 win_T *wp, 1456 linenr_T lnum, 1457 colnr_T startcol, 1458 char_u **text, 1459 int *textcol, // column where "text" starts, can be NULL 1460 int find_type) 1461 { 1462 char_u *ptr; 1463 int col = 0; // init to shut up GCC 1464 int i; 1465 int this_class = 0; 1466 int prev_class; 1467 int prevcol; 1468 int bn = 0; // bracket nesting 1469 1470 /* 1471 * if i == 0: try to find an identifier 1472 * if i == 1: try to find any non-white text 1473 */ 1474 ptr = ml_get_buf(wp->w_buffer, lnum, FALSE); 1475 for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; ++i) 1476 { 1477 /* 1478 * 1. skip to start of identifier/text 1479 */ 1480 col = startcol; 1481 if (has_mbyte) 1482 { 1483 while (ptr[col] != NUL) 1484 { 1485 // Stop at a ']' to evaluate "a[x]". 1486 if ((find_type & FIND_EVAL) && ptr[col] == ']') 1487 break; 1488 this_class = mb_get_class(ptr + col); 1489 if (this_class != 0 && (i == 1 || this_class != 1)) 1490 break; 1491 col += (*mb_ptr2len)(ptr + col); 1492 } 1493 } 1494 else 1495 while (ptr[col] != NUL 1496 && (i == 0 ? !vim_iswordc(ptr[col]) : VIM_ISWHITE(ptr[col])) 1497 && (!(find_type & FIND_EVAL) || ptr[col] != ']') 1498 ) 1499 ++col; 1500 1501 // When starting on a ']' count it, so that we include the '['. 1502 bn = ptr[col] == ']'; 1503 1504 /* 1505 * 2. Back up to start of identifier/text. 1506 */ 1507 if (has_mbyte) 1508 { 1509 // Remember class of character under cursor. 1510 if ((find_type & FIND_EVAL) && ptr[col] == ']') 1511 this_class = mb_get_class((char_u *)"a"); 1512 else 1513 this_class = mb_get_class(ptr + col); 1514 while (col > 0 && this_class != 0) 1515 { 1516 prevcol = col - 1 - (*mb_head_off)(ptr, ptr + col - 1); 1517 prev_class = mb_get_class(ptr + prevcol); 1518 if (this_class != prev_class 1519 && (i == 0 1520 || prev_class == 0 1521 || (find_type & FIND_IDENT)) 1522 && (!(find_type & FIND_EVAL) 1523 || prevcol == 0 1524 || !find_is_eval_item(ptr + prevcol, &prevcol, 1525 &bn, BACKWARD)) 1526 ) 1527 break; 1528 col = prevcol; 1529 } 1530 1531 // If we don't want just any old text, or we've found an 1532 // identifier, stop searching. 1533 if (this_class > 2) 1534 this_class = 2; 1535 if (!(find_type & FIND_STRING) || this_class == 2) 1536 break; 1537 } 1538 else 1539 { 1540 while (col > 0 1541 && ((i == 0 1542 ? vim_iswordc(ptr[col - 1]) 1543 : (!VIM_ISWHITE(ptr[col - 1]) 1544 && (!(find_type & FIND_IDENT) 1545 || !vim_iswordc(ptr[col - 1])))) 1546 || ((find_type & FIND_EVAL) 1547 && col > 1 1548 && find_is_eval_item(ptr + col - 1, &col, 1549 &bn, BACKWARD)) 1550 )) 1551 --col; 1552 1553 // If we don't want just any old text, or we've found an 1554 // identifier, stop searching. 1555 if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col])) 1556 break; 1557 } 1558 } 1559 1560 if (ptr[col] == NUL || (i == 0 1561 && (has_mbyte ? this_class != 2 : !vim_iswordc(ptr[col])))) 1562 { 1563 // didn't find an identifier or text 1564 if ((find_type & FIND_NOERROR) == 0) 1565 { 1566 if (find_type & FIND_STRING) 1567 emsg(_("E348: No string under cursor")); 1568 else 1569 emsg(_(e_noident)); 1570 } 1571 return 0; 1572 } 1573 ptr += col; 1574 *text = ptr; 1575 if (textcol != NULL) 1576 *textcol = col; 1577 1578 /* 1579 * 3. Find the end if the identifier/text. 1580 */ 1581 bn = 0; 1582 startcol -= col; 1583 col = 0; 1584 if (has_mbyte) 1585 { 1586 // Search for point of changing multibyte character class. 1587 this_class = mb_get_class(ptr); 1588 while (ptr[col] != NUL 1589 && ((i == 0 ? mb_get_class(ptr + col) == this_class 1590 : mb_get_class(ptr + col) != 0) 1591 || ((find_type & FIND_EVAL) 1592 && col <= (int)startcol 1593 && find_is_eval_item(ptr + col, &col, &bn, FORWARD)) 1594 )) 1595 col += (*mb_ptr2len)(ptr + col); 1596 } 1597 else 1598 while ((i == 0 ? vim_iswordc(ptr[col]) 1599 : (ptr[col] != NUL && !VIM_ISWHITE(ptr[col]))) 1600 || ((find_type & FIND_EVAL) 1601 && col <= (int)startcol 1602 && find_is_eval_item(ptr + col, &col, &bn, FORWARD)) 1603 ) 1604 ++col; 1605 1606 return col; 1607 } 1608 1609 /* 1610 * Prepare for redo of a normal command. 1611 */ 1612 static void 1613 prep_redo_cmd(cmdarg_T *cap) 1614 { 1615 prep_redo(cap->oap->regname, cap->count0, 1616 NUL, cap->cmdchar, NUL, NUL, cap->nchar); 1617 } 1618 1619 /* 1620 * Prepare for redo of any command. 1621 * Note that only the last argument can be a multi-byte char. 1622 */ 1623 void 1624 prep_redo( 1625 int regname, 1626 long num, 1627 int cmd1, 1628 int cmd2, 1629 int cmd3, 1630 int cmd4, 1631 int cmd5) 1632 { 1633 ResetRedobuff(); 1634 if (regname != 0) // yank from specified buffer 1635 { 1636 AppendCharToRedobuff('"'); 1637 AppendCharToRedobuff(regname); 1638 } 1639 if (num) 1640 AppendNumberToRedobuff(num); 1641 1642 if (cmd1 != NUL) 1643 AppendCharToRedobuff(cmd1); 1644 if (cmd2 != NUL) 1645 AppendCharToRedobuff(cmd2); 1646 if (cmd3 != NUL) 1647 AppendCharToRedobuff(cmd3); 1648 if (cmd4 != NUL) 1649 AppendCharToRedobuff(cmd4); 1650 if (cmd5 != NUL) 1651 AppendCharToRedobuff(cmd5); 1652 } 1653 1654 /* 1655 * check for operator active and clear it 1656 * 1657 * return TRUE if operator was active 1658 */ 1659 static int 1660 checkclearop(oparg_T *oap) 1661 { 1662 if (oap->op_type == OP_NOP) 1663 return FALSE; 1664 clearopbeep(oap); 1665 return TRUE; 1666 } 1667 1668 /* 1669 * Check for operator or Visual active. Clear active operator. 1670 * 1671 * Return TRUE if operator or Visual was active. 1672 */ 1673 static int 1674 checkclearopq(oparg_T *oap) 1675 { 1676 if (oap->op_type == OP_NOP && !VIsual_active) 1677 return FALSE; 1678 clearopbeep(oap); 1679 return TRUE; 1680 } 1681 1682 void 1683 clearop(oparg_T *oap) 1684 { 1685 oap->op_type = OP_NOP; 1686 oap->regname = 0; 1687 oap->motion_force = NUL; 1688 oap->use_reg_one = FALSE; 1689 } 1690 1691 void 1692 clearopbeep(oparg_T *oap) 1693 { 1694 clearop(oap); 1695 beep_flush(); 1696 } 1697 1698 /* 1699 * Remove the shift modifier from a special key. 1700 */ 1701 static void 1702 unshift_special(cmdarg_T *cap) 1703 { 1704 switch (cap->cmdchar) 1705 { 1706 case K_S_RIGHT: cap->cmdchar = K_RIGHT; break; 1707 case K_S_LEFT: cap->cmdchar = K_LEFT; break; 1708 case K_S_UP: cap->cmdchar = K_UP; break; 1709 case K_S_DOWN: cap->cmdchar = K_DOWN; break; 1710 case K_S_HOME: cap->cmdchar = K_HOME; break; 1711 case K_S_END: cap->cmdchar = K_END; break; 1712 } 1713 cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask); 1714 } 1715 1716 /* 1717 * If the mode is currently displayed clear the command line or update the 1718 * command displayed. 1719 */ 1720 void 1721 may_clear_cmdline(void) 1722 { 1723 if (mode_displayed) 1724 clear_cmdline = TRUE; // unshow visual mode later 1725 #ifdef FEAT_CMDL_INFO 1726 else 1727 clear_showcmd(); 1728 #endif 1729 } 1730 1731 #if defined(FEAT_CMDL_INFO) || defined(PROTO) 1732 /* 1733 * Routines for displaying a partly typed command 1734 */ 1735 1736 #define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30 1737 static char_u showcmd_buf[SHOWCMD_BUFLEN]; 1738 static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd() 1739 static int showcmd_is_clear = TRUE; 1740 static int showcmd_visual = FALSE; 1741 1742 static void display_showcmd(void); 1743 1744 void 1745 clear_showcmd(void) 1746 { 1747 if (!p_sc) 1748 return; 1749 1750 if (VIsual_active && !char_avail()) 1751 { 1752 int cursor_bot = LT_POS(VIsual, curwin->w_cursor); 1753 long lines; 1754 colnr_T leftcol, rightcol; 1755 linenr_T top, bot; 1756 1757 // Show the size of the Visual area. 1758 if (cursor_bot) 1759 { 1760 top = VIsual.lnum; 1761 bot = curwin->w_cursor.lnum; 1762 } 1763 else 1764 { 1765 top = curwin->w_cursor.lnum; 1766 bot = VIsual.lnum; 1767 } 1768 # ifdef FEAT_FOLDING 1769 // Include closed folds as a whole. 1770 (void)hasFolding(top, &top, NULL); 1771 (void)hasFolding(bot, NULL, &bot); 1772 # endif 1773 lines = bot - top + 1; 1774 1775 if (VIsual_mode == Ctrl_V) 1776 { 1777 # ifdef FEAT_LINEBREAK 1778 char_u *saved_sbr = p_sbr; 1779 char_u *saved_w_sbr = curwin->w_p_sbr; 1780 1781 // Make 'sbr' empty for a moment to get the correct size. 1782 p_sbr = empty_option; 1783 curwin->w_p_sbr = empty_option; 1784 # endif 1785 getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol); 1786 # ifdef FEAT_LINEBREAK 1787 p_sbr = saved_sbr; 1788 curwin->w_p_sbr = saved_w_sbr; 1789 # endif 1790 sprintf((char *)showcmd_buf, "%ldx%ld", lines, 1791 (long)(rightcol - leftcol + 1)); 1792 } 1793 else if (VIsual_mode == 'V' || VIsual.lnum != curwin->w_cursor.lnum) 1794 sprintf((char *)showcmd_buf, "%ld", lines); 1795 else 1796 { 1797 char_u *s, *e; 1798 int l; 1799 int bytes = 0; 1800 int chars = 0; 1801 1802 if (cursor_bot) 1803 { 1804 s = ml_get_pos(&VIsual); 1805 e = ml_get_cursor(); 1806 } 1807 else 1808 { 1809 s = ml_get_cursor(); 1810 e = ml_get_pos(&VIsual); 1811 } 1812 while ((*p_sel != 'e') ? s <= e : s < e) 1813 { 1814 l = (*mb_ptr2len)(s); 1815 if (l == 0) 1816 { 1817 ++bytes; 1818 ++chars; 1819 break; // end of line 1820 } 1821 bytes += l; 1822 ++chars; 1823 s += l; 1824 } 1825 if (bytes == chars) 1826 sprintf((char *)showcmd_buf, "%d", chars); 1827 else 1828 sprintf((char *)showcmd_buf, "%d-%d", chars, bytes); 1829 } 1830 showcmd_buf[SHOWCMD_COLS] = NUL; // truncate 1831 showcmd_visual = TRUE; 1832 } 1833 else 1834 { 1835 showcmd_buf[0] = NUL; 1836 showcmd_visual = FALSE; 1837 1838 // Don't actually display something if there is nothing to clear. 1839 if (showcmd_is_clear) 1840 return; 1841 } 1842 1843 display_showcmd(); 1844 } 1845 1846 /* 1847 * Add 'c' to string of shown command chars. 1848 * Return TRUE if output has been written (and setcursor() has been called). 1849 */ 1850 int 1851 add_to_showcmd(int c) 1852 { 1853 char_u *p; 1854 int old_len; 1855 int extra_len; 1856 int overflow; 1857 int i; 1858 static int ignore[] = 1859 { 1860 #ifdef FEAT_GUI 1861 K_VER_SCROLLBAR, K_HOR_SCROLLBAR, 1862 K_LEFTMOUSE_NM, K_LEFTRELEASE_NM, 1863 #endif 1864 K_IGNORE, K_PS, 1865 K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE, K_MOUSEMOVE, 1866 K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE, 1867 K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE, 1868 K_MOUSEDOWN, K_MOUSEUP, K_MOUSELEFT, K_MOUSERIGHT, 1869 K_X1MOUSE, K_X1DRAG, K_X1RELEASE, K_X2MOUSE, K_X2DRAG, K_X2RELEASE, 1870 K_CURSORHOLD, 1871 0 1872 }; 1873 1874 if (!p_sc || msg_silent != 0) 1875 return FALSE; 1876 1877 if (showcmd_visual) 1878 { 1879 showcmd_buf[0] = NUL; 1880 showcmd_visual = FALSE; 1881 } 1882 1883 // Ignore keys that are scrollbar updates and mouse clicks 1884 if (IS_SPECIAL(c)) 1885 for (i = 0; ignore[i] != 0; ++i) 1886 if (ignore[i] == c) 1887 return FALSE; 1888 1889 p = transchar(c); 1890 if (*p == ' ') 1891 STRCPY(p, "<20>"); 1892 old_len = (int)STRLEN(showcmd_buf); 1893 extra_len = (int)STRLEN(p); 1894 overflow = old_len + extra_len - SHOWCMD_COLS; 1895 if (overflow > 0) 1896 mch_memmove(showcmd_buf, showcmd_buf + overflow, 1897 old_len - overflow + 1); 1898 STRCAT(showcmd_buf, p); 1899 1900 if (char_avail()) 1901 return FALSE; 1902 1903 display_showcmd(); 1904 1905 return TRUE; 1906 } 1907 1908 void 1909 add_to_showcmd_c(int c) 1910 { 1911 if (!add_to_showcmd(c)) 1912 setcursor(); 1913 } 1914 1915 /* 1916 * Delete 'len' characters from the end of the shown command. 1917 */ 1918 static void 1919 del_from_showcmd(int len) 1920 { 1921 int old_len; 1922 1923 if (!p_sc) 1924 return; 1925 1926 old_len = (int)STRLEN(showcmd_buf); 1927 if (len > old_len) 1928 len = old_len; 1929 showcmd_buf[old_len - len] = NUL; 1930 1931 if (!char_avail()) 1932 display_showcmd(); 1933 } 1934 1935 /* 1936 * push_showcmd() and pop_showcmd() are used when waiting for the user to type 1937 * something and there is a partial mapping. 1938 */ 1939 void 1940 push_showcmd(void) 1941 { 1942 if (p_sc) 1943 STRCPY(old_showcmd_buf, showcmd_buf); 1944 } 1945 1946 void 1947 pop_showcmd(void) 1948 { 1949 if (!p_sc) 1950 return; 1951 1952 STRCPY(showcmd_buf, old_showcmd_buf); 1953 1954 display_showcmd(); 1955 } 1956 1957 static void 1958 display_showcmd(void) 1959 { 1960 int len; 1961 1962 cursor_off(); 1963 1964 len = (int)STRLEN(showcmd_buf); 1965 if (len == 0) 1966 showcmd_is_clear = TRUE; 1967 else 1968 { 1969 screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0); 1970 showcmd_is_clear = FALSE; 1971 } 1972 1973 /* 1974 * clear the rest of an old message by outputting up to SHOWCMD_COLS 1975 * spaces 1976 */ 1977 screen_puts((char_u *)" " + len, (int)Rows - 1, sc_col + len, 0); 1978 1979 setcursor(); // put cursor back where it belongs 1980 } 1981 #endif 1982 1983 /* 1984 * When "check" is FALSE, prepare for commands that scroll the window. 1985 * When "check" is TRUE, take care of scroll-binding after the window has 1986 * scrolled. Called from normal_cmd() and edit(). 1987 */ 1988 void 1989 do_check_scrollbind(int check) 1990 { 1991 static win_T *old_curwin = NULL; 1992 static linenr_T old_topline = 0; 1993 #ifdef FEAT_DIFF 1994 static int old_topfill = 0; 1995 #endif 1996 static buf_T *old_buf = NULL; 1997 static colnr_T old_leftcol = 0; 1998 1999 if (check && curwin->w_p_scb) 2000 { 2001 // If a ":syncbind" command was just used, don't scroll, only reset 2002 // the values. 2003 if (did_syncbind) 2004 did_syncbind = FALSE; 2005 else if (curwin == old_curwin) 2006 { 2007 /* 2008 * Synchronize other windows, as necessary according to 2009 * 'scrollbind'. Don't do this after an ":edit" command, except 2010 * when 'diff' is set. 2011 */ 2012 if ((curwin->w_buffer == old_buf 2013 #ifdef FEAT_DIFF 2014 || curwin->w_p_diff 2015 #endif 2016 ) 2017 && (curwin->w_topline != old_topline 2018 #ifdef FEAT_DIFF 2019 || curwin->w_topfill != old_topfill 2020 #endif 2021 || curwin->w_leftcol != old_leftcol)) 2022 { 2023 check_scrollbind(curwin->w_topline - old_topline, 2024 (long)(curwin->w_leftcol - old_leftcol)); 2025 } 2026 } 2027 else if (vim_strchr(p_sbo, 'j')) // jump flag set in 'scrollopt' 2028 { 2029 /* 2030 * When switching between windows, make sure that the relative 2031 * vertical offset is valid for the new window. The relative 2032 * offset is invalid whenever another 'scrollbind' window has 2033 * scrolled to a point that would force the current window to 2034 * scroll past the beginning or end of its buffer. When the 2035 * resync is performed, some of the other 'scrollbind' windows may 2036 * need to jump so that the current window's relative position is 2037 * visible on-screen. 2038 */ 2039 check_scrollbind(curwin->w_topline - curwin->w_scbind_pos, 0L); 2040 } 2041 curwin->w_scbind_pos = curwin->w_topline; 2042 } 2043 2044 old_curwin = curwin; 2045 old_topline = curwin->w_topline; 2046 #ifdef FEAT_DIFF 2047 old_topfill = curwin->w_topfill; 2048 #endif 2049 old_buf = curwin->w_buffer; 2050 old_leftcol = curwin->w_leftcol; 2051 } 2052 2053 /* 2054 * Synchronize any windows that have "scrollbind" set, based on the 2055 * number of rows by which the current window has changed 2056 * (1998-11-02 16:21:01 R. Edward Ralston <[email protected]>) 2057 */ 2058 void 2059 check_scrollbind(linenr_T topline_diff, long leftcol_diff) 2060 { 2061 int want_ver; 2062 int want_hor; 2063 win_T *old_curwin = curwin; 2064 buf_T *old_curbuf = curbuf; 2065 int old_VIsual_select = VIsual_select; 2066 int old_VIsual_active = VIsual_active; 2067 colnr_T tgt_leftcol = curwin->w_leftcol; 2068 long topline; 2069 long y; 2070 2071 /* 2072 * check 'scrollopt' string for vertical and horizontal scroll options 2073 */ 2074 want_ver = (vim_strchr(p_sbo, 'v') && topline_diff != 0); 2075 #ifdef FEAT_DIFF 2076 want_ver |= old_curwin->w_p_diff; 2077 #endif 2078 want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || topline_diff != 0)); 2079 2080 /* 2081 * loop through the scrollbound windows and scroll accordingly 2082 */ 2083 VIsual_select = VIsual_active = 0; 2084 FOR_ALL_WINDOWS(curwin) 2085 { 2086 curbuf = curwin->w_buffer; 2087 // skip original window and windows with 'noscrollbind' 2088 if (curwin != old_curwin && curwin->w_p_scb) 2089 { 2090 /* 2091 * do the vertical scroll 2092 */ 2093 if (want_ver) 2094 { 2095 #ifdef FEAT_DIFF 2096 if (old_curwin->w_p_diff && curwin->w_p_diff) 2097 { 2098 diff_set_topline(old_curwin, curwin); 2099 } 2100 else 2101 #endif 2102 { 2103 curwin->w_scbind_pos += topline_diff; 2104 topline = curwin->w_scbind_pos; 2105 if (topline > curbuf->b_ml.ml_line_count) 2106 topline = curbuf->b_ml.ml_line_count; 2107 if (topline < 1) 2108 topline = 1; 2109 2110 y = topline - curwin->w_topline; 2111 if (y > 0) 2112 scrollup(y, FALSE); 2113 else 2114 scrolldown(-y, FALSE); 2115 } 2116 2117 redraw_later(VALID); 2118 cursor_correct(); 2119 curwin->w_redr_status = TRUE; 2120 } 2121 2122 /* 2123 * do the horizontal scroll 2124 */ 2125 if (want_hor && curwin->w_leftcol != tgt_leftcol) 2126 { 2127 curwin->w_leftcol = tgt_leftcol; 2128 leftcol_changed(); 2129 } 2130 } 2131 } 2132 2133 /* 2134 * reset current-window 2135 */ 2136 VIsual_select = old_VIsual_select; 2137 VIsual_active = old_VIsual_active; 2138 curwin = old_curwin; 2139 curbuf = old_curbuf; 2140 } 2141 2142 /* 2143 * Command character that's ignored. 2144 * Used for CTRL-Q and CTRL-S to avoid problems with terminals that use 2145 * xon/xoff. 2146 */ 2147 static void 2148 nv_ignore(cmdarg_T *cap) 2149 { 2150 cap->retval |= CA_COMMAND_BUSY; // don't call edit() now 2151 } 2152 2153 /* 2154 * Command character that doesn't do anything, but unlike nv_ignore() does 2155 * start edit(). Used for "startinsert" executed while starting up. 2156 */ 2157 static void 2158 nv_nop(cmdarg_T *cap UNUSED) 2159 { 2160 } 2161 2162 /* 2163 * Command character doesn't exist. 2164 */ 2165 static void 2166 nv_error(cmdarg_T *cap) 2167 { 2168 clearopbeep(cap->oap); 2169 } 2170 2171 /* 2172 * <Help> and <F1> commands. 2173 */ 2174 static void 2175 nv_help(cmdarg_T *cap) 2176 { 2177 if (!checkclearopq(cap->oap)) 2178 ex_help(NULL); 2179 } 2180 2181 /* 2182 * CTRL-A and CTRL-X: Add or subtract from letter or number under cursor. 2183 */ 2184 static void 2185 nv_addsub(cmdarg_T *cap) 2186 { 2187 #ifdef FEAT_JOB_CHANNEL 2188 if (bt_prompt(curbuf) && !prompt_curpos_editable()) 2189 clearopbeep(cap->oap); 2190 else 2191 #endif 2192 if (!VIsual_active && cap->oap->op_type == OP_NOP) 2193 { 2194 prep_redo_cmd(cap); 2195 cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB; 2196 op_addsub(cap->oap, cap->count1, cap->arg); 2197 cap->oap->op_type = OP_NOP; 2198 } 2199 else if (VIsual_active) 2200 nv_operator(cap); 2201 else 2202 clearop(cap->oap); 2203 } 2204 2205 /* 2206 * CTRL-F, CTRL-B, etc: Scroll page up or down. 2207 */ 2208 static void 2209 nv_page(cmdarg_T *cap) 2210 { 2211 if (!checkclearop(cap->oap)) 2212 { 2213 if (mod_mask & MOD_MASK_CTRL) 2214 { 2215 // <C-PageUp>: tab page back; <C-PageDown>: tab page forward 2216 if (cap->arg == BACKWARD) 2217 goto_tabpage(-(int)cap->count1); 2218 else 2219 goto_tabpage((int)cap->count0); 2220 } 2221 else 2222 (void)onepage(cap->arg, cap->count1); 2223 } 2224 } 2225 2226 /* 2227 * Implementation of "gd" and "gD" command. 2228 */ 2229 static void 2230 nv_gd( 2231 oparg_T *oap, 2232 int nchar, 2233 int thisblock) // 1 for "1gd" and "1gD" 2234 { 2235 int len; 2236 char_u *ptr; 2237 2238 if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 2239 || find_decl(ptr, len, nchar == 'd', thisblock, SEARCH_START) 2240 == FAIL) 2241 clearopbeep(oap); 2242 #ifdef FEAT_FOLDING 2243 else if ((fdo_flags & FDO_SEARCH) && KeyTyped && oap->op_type == OP_NOP) 2244 foldOpenCursor(); 2245 #endif 2246 } 2247 2248 /* 2249 * Return TRUE if line[offset] is not inside a C-style comment or string, FALSE 2250 * otherwise. 2251 */ 2252 static int 2253 is_ident(char_u *line, int offset) 2254 { 2255 int i; 2256 int incomment = FALSE; 2257 int instring = 0; 2258 int prev = 0; 2259 2260 for (i = 0; i < offset && line[i] != NUL; i++) 2261 { 2262 if (instring != 0) 2263 { 2264 if (prev != '\\' && line[i] == instring) 2265 instring = 0; 2266 } 2267 else if ((line[i] == '"' || line[i] == '\'') && !incomment) 2268 { 2269 instring = line[i]; 2270 } 2271 else 2272 { 2273 if (incomment) 2274 { 2275 if (prev == '*' && line[i] == '/') 2276 incomment = FALSE; 2277 } 2278 else if (prev == '/' && line[i] == '*') 2279 { 2280 incomment = TRUE; 2281 } 2282 else if (prev == '/' && line[i] == '/') 2283 { 2284 return FALSE; 2285 } 2286 } 2287 2288 prev = line[i]; 2289 } 2290 2291 return incomment == FALSE && instring == 0; 2292 } 2293 2294 /* 2295 * Search for variable declaration of "ptr[len]". 2296 * When "locally" is TRUE in the current function ("gd"), otherwise in the 2297 * current file ("gD"). 2298 * When "thisblock" is TRUE check the {} block scope. 2299 * Return FAIL when not found. 2300 */ 2301 int 2302 find_decl( 2303 char_u *ptr, 2304 int len, 2305 int locally, 2306 int thisblock, 2307 int flags_arg) // flags passed to searchit() 2308 { 2309 char_u *pat; 2310 pos_T old_pos; 2311 pos_T par_pos; 2312 pos_T found_pos; 2313 int t; 2314 int save_p_ws; 2315 int save_p_scs; 2316 int retval = OK; 2317 int incll; 2318 int searchflags = flags_arg; 2319 int valid; 2320 2321 if ((pat = alloc(len + 7)) == NULL) 2322 return FAIL; 2323 2324 // Put "\V" before the pattern to avoid that the special meaning of "." 2325 // and "~" causes trouble. 2326 sprintf((char *)pat, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", 2327 len, ptr); 2328 old_pos = curwin->w_cursor; 2329 save_p_ws = p_ws; 2330 save_p_scs = p_scs; 2331 p_ws = FALSE; // don't wrap around end of file now 2332 p_scs = FALSE; // don't switch ignorecase off now 2333 2334 /* 2335 * With "gD" go to line 1. 2336 * With "gd" Search back for the start of the current function, then go 2337 * back until a blank line. If this fails go to line 1. 2338 */ 2339 if (!locally || !findpar(&incll, BACKWARD, 1L, '{', FALSE)) 2340 { 2341 setpcmark(); // Set in findpar() otherwise 2342 curwin->w_cursor.lnum = 1; 2343 par_pos = curwin->w_cursor; 2344 } 2345 else 2346 { 2347 par_pos = curwin->w_cursor; 2348 while (curwin->w_cursor.lnum > 1 && *skipwhite(ml_get_curline()) != NUL) 2349 --curwin->w_cursor.lnum; 2350 } 2351 curwin->w_cursor.col = 0; 2352 2353 // Search forward for the identifier, ignore comment lines. 2354 CLEAR_POS(&found_pos); 2355 for (;;) 2356 { 2357 t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD, 2358 pat, 1L, searchflags, RE_LAST, NULL); 2359 if (curwin->w_cursor.lnum >= old_pos.lnum) 2360 t = FAIL; // match after start is failure too 2361 2362 if (thisblock && t != FAIL) 2363 { 2364 pos_T *pos; 2365 2366 // Check that the block the match is in doesn't end before the 2367 // position where we started the search from. 2368 if ((pos = findmatchlimit(NULL, '}', FM_FORWARD, 2369 (int)(old_pos.lnum - curwin->w_cursor.lnum + 1))) != NULL 2370 && pos->lnum < old_pos.lnum) 2371 { 2372 // There can't be a useful match before the end of this block. 2373 // Skip to the end. 2374 curwin->w_cursor = *pos; 2375 continue; 2376 } 2377 } 2378 2379 if (t == FAIL) 2380 { 2381 // If we previously found a valid position, use it. 2382 if (found_pos.lnum != 0) 2383 { 2384 curwin->w_cursor = found_pos; 2385 t = OK; 2386 } 2387 break; 2388 } 2389 if (get_leader_len(ml_get_curline(), NULL, FALSE, TRUE) > 0) 2390 { 2391 // Ignore this line, continue at start of next line. 2392 ++curwin->w_cursor.lnum; 2393 curwin->w_cursor.col = 0; 2394 continue; 2395 } 2396 valid = is_ident(ml_get_curline(), curwin->w_cursor.col); 2397 2398 // If the current position is not a valid identifier and a previous 2399 // match is present, favor that one instead. 2400 if (!valid && found_pos.lnum != 0) 2401 { 2402 curwin->w_cursor = found_pos; 2403 break; 2404 } 2405 2406 // Global search: use first valid match found 2407 if (valid && !locally) 2408 break; 2409 if (valid && curwin->w_cursor.lnum >= par_pos.lnum) 2410 { 2411 // If we previously found a valid position, use it. 2412 if (found_pos.lnum != 0) 2413 curwin->w_cursor = found_pos; 2414 break; 2415 } 2416 2417 // For finding a local variable and the match is before the "{" or 2418 // inside a comment, continue searching. For K&R style function 2419 // declarations this skips the function header without types. 2420 if (!valid) 2421 CLEAR_POS(&found_pos); 2422 else 2423 found_pos = curwin->w_cursor; 2424 // Remove SEARCH_START from flags to avoid getting stuck at one 2425 // position. 2426 searchflags &= ~SEARCH_START; 2427 } 2428 2429 if (t == FAIL) 2430 { 2431 retval = FAIL; 2432 curwin->w_cursor = old_pos; 2433 } 2434 else 2435 { 2436 curwin->w_set_curswant = TRUE; 2437 // "n" searches forward now 2438 reset_search_dir(); 2439 } 2440 2441 vim_free(pat); 2442 p_ws = save_p_ws; 2443 p_scs = save_p_scs; 2444 2445 return retval; 2446 } 2447 2448 /* 2449 * Move 'dist' lines in direction 'dir', counting lines by *screen* 2450 * lines rather than lines in the file. 2451 * 'dist' must be positive. 2452 * 2453 * Return OK if able to move cursor, FAIL otherwise. 2454 */ 2455 static int 2456 nv_screengo(oparg_T *oap, int dir, long dist) 2457 { 2458 int linelen = linetabsize(ml_get_curline()); 2459 int retval = OK; 2460 int atend = FALSE; 2461 int n; 2462 int col_off1; // margin offset for first screen line 2463 int col_off2; // margin offset for wrapped screen line 2464 int width1; // text width for first screen line 2465 int width2; // test width for wrapped screen line 2466 2467 oap->motion_type = MCHAR; 2468 oap->inclusive = (curwin->w_curswant == MAXCOL); 2469 2470 col_off1 = curwin_col_off(); 2471 col_off2 = col_off1 - curwin_col_off2(); 2472 width1 = curwin->w_width - col_off1; 2473 width2 = curwin->w_width - col_off2; 2474 if (width2 == 0) 2475 width2 = 1; // avoid divide by zero 2476 2477 if (curwin->w_width != 0) 2478 { 2479 /* 2480 * Instead of sticking at the last character of the buffer line we 2481 * try to stick in the last column of the screen. 2482 */ 2483 if (curwin->w_curswant == MAXCOL) 2484 { 2485 atend = TRUE; 2486 validate_virtcol(); 2487 if (width1 <= 0) 2488 curwin->w_curswant = 0; 2489 else 2490 { 2491 curwin->w_curswant = width1 - 1; 2492 if (curwin->w_virtcol > curwin->w_curswant) 2493 curwin->w_curswant += ((curwin->w_virtcol 2494 - curwin->w_curswant - 1) / width2 + 1) * width2; 2495 } 2496 } 2497 else 2498 { 2499 if (linelen > width1) 2500 n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1; 2501 else 2502 n = width1; 2503 if (curwin->w_curswant >= (colnr_T)n) 2504 curwin->w_curswant = n - 1; 2505 } 2506 2507 while (dist--) 2508 { 2509 if (dir == BACKWARD) 2510 { 2511 if ((long)curwin->w_curswant >= width1) 2512 // Move back within the line. This can give a negative value 2513 // for w_curswant if width1 < width2 (with cpoptions+=n), 2514 // which will get clipped to column 0. 2515 curwin->w_curswant -= width2; 2516 else 2517 { 2518 // to previous line 2519 if (curwin->w_cursor.lnum == 1) 2520 { 2521 retval = FAIL; 2522 break; 2523 } 2524 --curwin->w_cursor.lnum; 2525 #ifdef FEAT_FOLDING 2526 // Move to the start of a closed fold. Don't do that when 2527 // 'foldopen' contains "all": it will open in a moment. 2528 if (!(fdo_flags & FDO_ALL)) 2529 (void)hasFolding(curwin->w_cursor.lnum, 2530 &curwin->w_cursor.lnum, NULL); 2531 #endif 2532 linelen = linetabsize(ml_get_curline()); 2533 if (linelen > width1) 2534 curwin->w_curswant += (((linelen - width1 - 1) / width2) 2535 + 1) * width2; 2536 } 2537 } 2538 else // dir == FORWARD 2539 { 2540 if (linelen > width1) 2541 n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1; 2542 else 2543 n = width1; 2544 if (curwin->w_curswant + width2 < (colnr_T)n) 2545 // move forward within line 2546 curwin->w_curswant += width2; 2547 else 2548 { 2549 // to next line 2550 #ifdef FEAT_FOLDING 2551 // Move to the end of a closed fold. 2552 (void)hasFolding(curwin->w_cursor.lnum, NULL, 2553 &curwin->w_cursor.lnum); 2554 #endif 2555 if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) 2556 { 2557 retval = FAIL; 2558 break; 2559 } 2560 curwin->w_cursor.lnum++; 2561 curwin->w_curswant %= width2; 2562 // Check if the cursor has moved below the number display 2563 // when width1 < width2 (with cpoptions+=n). Subtract width2 2564 // to get a negative value for w_curswant, which will get 2565 // clipped to column 0. 2566 if (curwin->w_curswant >= width1) 2567 curwin->w_curswant -= width2; 2568 linelen = linetabsize(ml_get_curline()); 2569 } 2570 } 2571 } 2572 } 2573 2574 if (virtual_active() && atend) 2575 coladvance(MAXCOL); 2576 else 2577 coladvance(curwin->w_curswant); 2578 2579 if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) 2580 { 2581 colnr_T virtcol; 2582 2583 /* 2584 * Check for landing on a character that got split at the end of the 2585 * last line. We want to advance a screenline, not end up in the same 2586 * screenline or move two screenlines. 2587 */ 2588 validate_virtcol(); 2589 virtcol = curwin->w_virtcol; 2590 #if defined(FEAT_LINEBREAK) 2591 if (virtcol > (colnr_T)width1 && *get_showbreak_value(curwin) != NUL) 2592 virtcol -= vim_strsize(get_showbreak_value(curwin)); 2593 #endif 2594 2595 if (virtcol > curwin->w_curswant 2596 && (curwin->w_curswant < (colnr_T)width1 2597 ? (curwin->w_curswant > (colnr_T)width1 / 2) 2598 : ((curwin->w_curswant - width1) % width2 2599 > (colnr_T)width2 / 2))) 2600 --curwin->w_cursor.col; 2601 } 2602 2603 if (atend) 2604 curwin->w_curswant = MAXCOL; // stick in the last column 2605 2606 return retval; 2607 } 2608 2609 /* 2610 * Handle CTRL-E and CTRL-Y commands: scroll a line up or down. 2611 * cap->arg must be TRUE for CTRL-E. 2612 */ 2613 void 2614 nv_scroll_line(cmdarg_T *cap) 2615 { 2616 if (!checkclearop(cap->oap)) 2617 scroll_redraw(cap->arg, cap->count1); 2618 } 2619 2620 /* 2621 * Scroll "count" lines up or down, and redraw. 2622 */ 2623 void 2624 scroll_redraw(int up, long count) 2625 { 2626 linenr_T prev_topline = curwin->w_topline; 2627 #ifdef FEAT_DIFF 2628 int prev_topfill = curwin->w_topfill; 2629 #endif 2630 linenr_T prev_lnum = curwin->w_cursor.lnum; 2631 2632 if (up) 2633 scrollup(count, TRUE); 2634 else 2635 scrolldown(count, TRUE); 2636 if (get_scrolloff_value()) 2637 { 2638 // Adjust the cursor position for 'scrolloff'. Mark w_topline as 2639 // valid, otherwise the screen jumps back at the end of the file. 2640 cursor_correct(); 2641 check_cursor_moved(curwin); 2642 curwin->w_valid |= VALID_TOPLINE; 2643 2644 // If moved back to where we were, at least move the cursor, otherwise 2645 // we get stuck at one position. Don't move the cursor up if the 2646 // first line of the buffer is already on the screen 2647 while (curwin->w_topline == prev_topline 2648 #ifdef FEAT_DIFF 2649 && curwin->w_topfill == prev_topfill 2650 #endif 2651 ) 2652 { 2653 if (up) 2654 { 2655 if (curwin->w_cursor.lnum > prev_lnum 2656 || cursor_down(1L, FALSE) == FAIL) 2657 break; 2658 } 2659 else 2660 { 2661 if (curwin->w_cursor.lnum < prev_lnum 2662 || prev_topline == 1L 2663 || cursor_up(1L, FALSE) == FAIL) 2664 break; 2665 } 2666 // Mark w_topline as valid, otherwise the screen jumps back at the 2667 // end of the file. 2668 check_cursor_moved(curwin); 2669 curwin->w_valid |= VALID_TOPLINE; 2670 } 2671 } 2672 if (curwin->w_cursor.lnum != prev_lnum) 2673 coladvance(curwin->w_curswant); 2674 redraw_later(VALID); 2675 } 2676 2677 /* 2678 * Commands that start with "z". 2679 */ 2680 static void 2681 nv_zet(cmdarg_T *cap) 2682 { 2683 long n; 2684 colnr_T col; 2685 int nchar = cap->nchar; 2686 #ifdef FEAT_FOLDING 2687 long old_fdl = curwin->w_p_fdl; 2688 int old_fen = curwin->w_p_fen; 2689 #endif 2690 #ifdef FEAT_SPELL 2691 int undo = FALSE; 2692 #endif 2693 long siso = get_sidescrolloff_value(); 2694 2695 if (VIM_ISDIGIT(nchar)) 2696 { 2697 /* 2698 * "z123{nchar}": edit the count before obtaining {nchar} 2699 */ 2700 if (checkclearop(cap->oap)) 2701 return; 2702 n = nchar - '0'; 2703 for (;;) 2704 { 2705 #ifdef USE_ON_FLY_SCROLL 2706 dont_scroll = TRUE; // disallow scrolling here 2707 #endif 2708 ++no_mapping; 2709 ++allow_keys; // no mapping for nchar, but allow key codes 2710 nchar = plain_vgetc(); 2711 LANGMAP_ADJUST(nchar, TRUE); 2712 --no_mapping; 2713 --allow_keys; 2714 #ifdef FEAT_CMDL_INFO 2715 (void)add_to_showcmd(nchar); 2716 #endif 2717 if (nchar == K_DEL || nchar == K_KDEL) 2718 n /= 10; 2719 else if (VIM_ISDIGIT(nchar)) 2720 n = n * 10 + (nchar - '0'); 2721 else if (nchar == CAR) 2722 { 2723 #ifdef FEAT_GUI 2724 need_mouse_correct = TRUE; 2725 #endif 2726 win_setheight((int)n); 2727 break; 2728 } 2729 else if (nchar == 'l' 2730 || nchar == 'h' 2731 || nchar == K_LEFT 2732 || nchar == K_RIGHT) 2733 { 2734 cap->count1 = n ? n * cap->count1 : cap->count1; 2735 goto dozet; 2736 } 2737 else 2738 { 2739 clearopbeep(cap->oap); 2740 break; 2741 } 2742 } 2743 cap->oap->op_type = OP_NOP; 2744 return; 2745 } 2746 2747 dozet: 2748 if ( 2749 #ifdef FEAT_FOLDING 2750 // "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc" 2751 // and "zC" only in Visual mode. "zj" and "zk" are motion 2752 // commands. 2753 cap->nchar != 'f' && cap->nchar != 'F' 2754 && !(VIsual_active && vim_strchr((char_u *)"dcCoO", cap->nchar)) 2755 && cap->nchar != 'j' && cap->nchar != 'k' 2756 && 2757 #endif 2758 checkclearop(cap->oap)) 2759 return; 2760 2761 /* 2762 * For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb": 2763 * If line number given, set cursor. 2764 */ 2765 if ((vim_strchr((char_u *)"+\r\nt.z^-b", nchar) != NULL) 2766 && cap->count0 2767 && cap->count0 != curwin->w_cursor.lnum) 2768 { 2769 setpcmark(); 2770 if (cap->count0 > curbuf->b_ml.ml_line_count) 2771 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 2772 else 2773 curwin->w_cursor.lnum = cap->count0; 2774 check_cursor_col(); 2775 } 2776 2777 switch (nchar) 2778 { 2779 // "z+", "z<CR>" and "zt": put cursor at top of screen 2780 case '+': 2781 if (cap->count0 == 0) 2782 { 2783 // No count given: put cursor at the line below screen 2784 validate_botline(); // make sure w_botline is valid 2785 if (curwin->w_botline > curbuf->b_ml.ml_line_count) 2786 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 2787 else 2788 curwin->w_cursor.lnum = curwin->w_botline; 2789 } 2790 // FALLTHROUGH 2791 case NL: 2792 case CAR: 2793 case K_KENTER: 2794 beginline(BL_WHITE | BL_FIX); 2795 // FALLTHROUGH 2796 2797 case 't': scroll_cursor_top(0, TRUE); 2798 redraw_later(VALID); 2799 set_fraction(curwin); 2800 break; 2801 2802 // "z." and "zz": put cursor in middle of screen 2803 case '.': beginline(BL_WHITE | BL_FIX); 2804 // FALLTHROUGH 2805 2806 case 'z': scroll_cursor_halfway(TRUE); 2807 redraw_later(VALID); 2808 set_fraction(curwin); 2809 break; 2810 2811 // "z^", "z-" and "zb": put cursor at bottom of screen 2812 case '^': // Strange Vi behavior: <count>z^ finds line at top of window 2813 // when <count> is at bottom of window, and puts that one at 2814 // bottom of window. 2815 if (cap->count0 != 0) 2816 { 2817 scroll_cursor_bot(0, TRUE); 2818 curwin->w_cursor.lnum = curwin->w_topline; 2819 } 2820 else if (curwin->w_topline == 1) 2821 curwin->w_cursor.lnum = 1; 2822 else 2823 curwin->w_cursor.lnum = curwin->w_topline - 1; 2824 // FALLTHROUGH 2825 case '-': 2826 beginline(BL_WHITE | BL_FIX); 2827 // FALLTHROUGH 2828 2829 case 'b': scroll_cursor_bot(0, TRUE); 2830 redraw_later(VALID); 2831 set_fraction(curwin); 2832 break; 2833 2834 // "zH" - scroll screen right half-page 2835 case 'H': 2836 cap->count1 *= curwin->w_width / 2; 2837 // FALLTHROUGH 2838 2839 // "zh" - scroll screen to the right 2840 case 'h': 2841 case K_LEFT: 2842 if (!curwin->w_p_wrap) 2843 { 2844 if ((colnr_T)cap->count1 > curwin->w_leftcol) 2845 curwin->w_leftcol = 0; 2846 else 2847 curwin->w_leftcol -= (colnr_T)cap->count1; 2848 leftcol_changed(); 2849 } 2850 break; 2851 2852 // "zL" - scroll screen left half-page 2853 case 'L': cap->count1 *= curwin->w_width / 2; 2854 // FALLTHROUGH 2855 2856 // "zl" - scroll screen to the left 2857 case 'l': 2858 case K_RIGHT: 2859 if (!curwin->w_p_wrap) 2860 { 2861 // scroll the window left 2862 curwin->w_leftcol += (colnr_T)cap->count1; 2863 leftcol_changed(); 2864 } 2865 break; 2866 2867 // "zs" - scroll screen, cursor at the start 2868 case 's': if (!curwin->w_p_wrap) 2869 { 2870 #ifdef FEAT_FOLDING 2871 if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) 2872 col = 0; // like the cursor is in col 0 2873 else 2874 #endif 2875 getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL); 2876 if ((long)col > siso) 2877 col -= siso; 2878 else 2879 col = 0; 2880 if (curwin->w_leftcol != col) 2881 { 2882 curwin->w_leftcol = col; 2883 redraw_later(NOT_VALID); 2884 } 2885 } 2886 break; 2887 2888 // "ze" - scroll screen, cursor at the end 2889 case 'e': if (!curwin->w_p_wrap) 2890 { 2891 #ifdef FEAT_FOLDING 2892 if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) 2893 col = 0; // like the cursor is in col 0 2894 else 2895 #endif 2896 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); 2897 n = curwin->w_width - curwin_col_off(); 2898 if ((long)col + siso < n) 2899 col = 0; 2900 else 2901 col = col + siso - n + 1; 2902 if (curwin->w_leftcol != col) 2903 { 2904 curwin->w_leftcol = col; 2905 redraw_later(NOT_VALID); 2906 } 2907 } 2908 break; 2909 2910 #ifdef FEAT_FOLDING 2911 // "zF": create fold command 2912 // "zf": create fold operator 2913 case 'F': 2914 case 'f': if (foldManualAllowed(TRUE)) 2915 { 2916 cap->nchar = 'f'; 2917 nv_operator(cap); 2918 curwin->w_p_fen = TRUE; 2919 2920 // "zF" is like "zfzf" 2921 if (nchar == 'F' && cap->oap->op_type == OP_FOLD) 2922 { 2923 nv_operator(cap); 2924 finish_op = TRUE; 2925 } 2926 } 2927 else 2928 clearopbeep(cap->oap); 2929 break; 2930 2931 // "zd": delete fold at cursor 2932 // "zD": delete fold at cursor recursively 2933 case 'd': 2934 case 'D': if (foldManualAllowed(FALSE)) 2935 { 2936 if (VIsual_active) 2937 nv_operator(cap); 2938 else 2939 deleteFold(curwin->w_cursor.lnum, 2940 curwin->w_cursor.lnum, nchar == 'D', FALSE); 2941 } 2942 break; 2943 2944 // "zE": erase all folds 2945 case 'E': if (foldmethodIsManual(curwin)) 2946 { 2947 clearFolding(curwin); 2948 changed_window_setting(); 2949 } 2950 else if (foldmethodIsMarker(curwin)) 2951 deleteFold((linenr_T)1, curbuf->b_ml.ml_line_count, 2952 TRUE, FALSE); 2953 else 2954 emsg(_("E352: Cannot erase folds with current 'foldmethod'")); 2955 break; 2956 2957 // "zn": fold none: reset 'foldenable' 2958 case 'n': curwin->w_p_fen = FALSE; 2959 break; 2960 2961 // "zN": fold Normal: set 'foldenable' 2962 case 'N': curwin->w_p_fen = TRUE; 2963 break; 2964 2965 // "zi": invert folding: toggle 'foldenable' 2966 case 'i': curwin->w_p_fen = !curwin->w_p_fen; 2967 break; 2968 2969 // "za": open closed fold or close open fold at cursor 2970 case 'a': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) 2971 openFold(curwin->w_cursor.lnum, cap->count1); 2972 else 2973 { 2974 closeFold(curwin->w_cursor.lnum, cap->count1); 2975 curwin->w_p_fen = TRUE; 2976 } 2977 break; 2978 2979 // "zA": open fold at cursor recursively 2980 case 'A': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) 2981 openFoldRecurse(curwin->w_cursor.lnum); 2982 else 2983 { 2984 closeFoldRecurse(curwin->w_cursor.lnum); 2985 curwin->w_p_fen = TRUE; 2986 } 2987 break; 2988 2989 // "zo": open fold at cursor or Visual area 2990 case 'o': if (VIsual_active) 2991 nv_operator(cap); 2992 else 2993 openFold(curwin->w_cursor.lnum, cap->count1); 2994 break; 2995 2996 // "zO": open fold recursively 2997 case 'O': if (VIsual_active) 2998 nv_operator(cap); 2999 else 3000 openFoldRecurse(curwin->w_cursor.lnum); 3001 break; 3002 3003 // "zc": close fold at cursor or Visual area 3004 case 'c': if (VIsual_active) 3005 nv_operator(cap); 3006 else 3007 closeFold(curwin->w_cursor.lnum, cap->count1); 3008 curwin->w_p_fen = TRUE; 3009 break; 3010 3011 // "zC": close fold recursively 3012 case 'C': if (VIsual_active) 3013 nv_operator(cap); 3014 else 3015 closeFoldRecurse(curwin->w_cursor.lnum); 3016 curwin->w_p_fen = TRUE; 3017 break; 3018 3019 // "zv": open folds at the cursor 3020 case 'v': foldOpenCursor(); 3021 break; 3022 3023 // "zx": re-apply 'foldlevel' and open folds at the cursor 3024 case 'x': curwin->w_p_fen = TRUE; 3025 curwin->w_foldinvalid = TRUE; // recompute folds 3026 newFoldLevel(); // update right now 3027 foldOpenCursor(); 3028 break; 3029 3030 // "zX": undo manual opens/closes, re-apply 'foldlevel' 3031 case 'X': curwin->w_p_fen = TRUE; 3032 curwin->w_foldinvalid = TRUE; // recompute folds 3033 old_fdl = -1; // force an update 3034 break; 3035 3036 // "zm": fold more 3037 case 'm': if (curwin->w_p_fdl > 0) 3038 { 3039 curwin->w_p_fdl -= cap->count1; 3040 if (curwin->w_p_fdl < 0) 3041 curwin->w_p_fdl = 0; 3042 } 3043 old_fdl = -1; // force an update 3044 curwin->w_p_fen = TRUE; 3045 break; 3046 3047 // "zM": close all folds 3048 case 'M': curwin->w_p_fdl = 0; 3049 old_fdl = -1; // force an update 3050 curwin->w_p_fen = TRUE; 3051 break; 3052 3053 // "zr": reduce folding 3054 case 'r': curwin->w_p_fdl += cap->count1; 3055 { 3056 int d = getDeepestNesting(); 3057 3058 if (curwin->w_p_fdl >= d) 3059 curwin->w_p_fdl = d; 3060 } 3061 break; 3062 3063 // "zR": open all folds 3064 case 'R': curwin->w_p_fdl = getDeepestNesting(); 3065 old_fdl = -1; // force an update 3066 break; 3067 3068 case 'j': // "zj" move to next fold downwards 3069 case 'k': // "zk" move to next fold upwards 3070 if (foldMoveTo(TRUE, nchar == 'j' ? FORWARD : BACKWARD, 3071 cap->count1) == FAIL) 3072 clearopbeep(cap->oap); 3073 break; 3074 3075 #endif // FEAT_FOLDING 3076 3077 #ifdef FEAT_SPELL 3078 case 'u': // "zug" and "zuw": undo "zg" and "zw" 3079 ++no_mapping; 3080 ++allow_keys; // no mapping for nchar, but allow key codes 3081 nchar = plain_vgetc(); 3082 LANGMAP_ADJUST(nchar, TRUE); 3083 --no_mapping; 3084 --allow_keys; 3085 #ifdef FEAT_CMDL_INFO 3086 (void)add_to_showcmd(nchar); 3087 #endif 3088 if (vim_strchr((char_u *)"gGwW", nchar) == NULL) 3089 { 3090 clearopbeep(cap->oap); 3091 break; 3092 } 3093 undo = TRUE; 3094 // FALLTHROUGH 3095 3096 case 'g': // "zg": add good word to word list 3097 case 'w': // "zw": add wrong word to word list 3098 case 'G': // "zG": add good word to temp word list 3099 case 'W': // "zW": add wrong word to temp word list 3100 { 3101 char_u *ptr = NULL; 3102 int len; 3103 3104 if (checkclearop(cap->oap)) 3105 break; 3106 if (VIsual_active && get_visual_text(cap, &ptr, &len) 3107 == FAIL) 3108 return; 3109 if (ptr == NULL) 3110 { 3111 pos_T pos = curwin->w_cursor; 3112 3113 // Find bad word under the cursor. When 'spell' is 3114 // off this fails and find_ident_under_cursor() is 3115 // used below. 3116 emsg_off++; 3117 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL); 3118 emsg_off--; 3119 if (len != 0 && curwin->w_cursor.col <= pos.col) 3120 ptr = ml_get_pos(&curwin->w_cursor); 3121 curwin->w_cursor = pos; 3122 } 3123 3124 if (ptr == NULL && (len = find_ident_under_cursor(&ptr, 3125 FIND_IDENT)) == 0) 3126 return; 3127 spell_add_word(ptr, len, nchar == 'w' || nchar == 'W' 3128 ? SPELL_ADD_BAD : SPELL_ADD_GOOD, 3129 (nchar == 'G' || nchar == 'W') 3130 ? 0 : (int)cap->count1, 3131 undo); 3132 } 3133 break; 3134 3135 case '=': // "z=": suggestions for a badly spelled word 3136 if (!checkclearop(cap->oap)) 3137 spell_suggest((int)cap->count0); 3138 break; 3139 #endif 3140 3141 default: clearopbeep(cap->oap); 3142 } 3143 3144 #ifdef FEAT_FOLDING 3145 // Redraw when 'foldenable' changed 3146 if (old_fen != curwin->w_p_fen) 3147 { 3148 # ifdef FEAT_DIFF 3149 win_T *wp; 3150 3151 if (foldmethodIsDiff(curwin) && curwin->w_p_scb) 3152 { 3153 // Adjust 'foldenable' in diff-synced windows. 3154 FOR_ALL_WINDOWS(wp) 3155 { 3156 if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) 3157 { 3158 wp->w_p_fen = curwin->w_p_fen; 3159 changed_window_setting_win(wp); 3160 } 3161 } 3162 } 3163 # endif 3164 changed_window_setting(); 3165 } 3166 3167 // Redraw when 'foldlevel' changed. 3168 if (old_fdl != curwin->w_p_fdl) 3169 newFoldLevel(); 3170 #endif 3171 } 3172 3173 #ifdef FEAT_GUI 3174 /* 3175 * Vertical scrollbar movement. 3176 */ 3177 static void 3178 nv_ver_scrollbar(cmdarg_T *cap) 3179 { 3180 if (cap->oap->op_type != OP_NOP) 3181 clearopbeep(cap->oap); 3182 3183 // Even if an operator was pending, we still want to scroll 3184 gui_do_scroll(); 3185 } 3186 3187 /* 3188 * Horizontal scrollbar movement. 3189 */ 3190 static void 3191 nv_hor_scrollbar(cmdarg_T *cap) 3192 { 3193 if (cap->oap->op_type != OP_NOP) 3194 clearopbeep(cap->oap); 3195 3196 // Even if an operator was pending, we still want to scroll 3197 gui_do_horiz_scroll(scrollbar_value, FALSE); 3198 } 3199 #endif 3200 3201 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) 3202 /* 3203 * Click in GUI tab. 3204 */ 3205 static void 3206 nv_tabline(cmdarg_T *cap) 3207 { 3208 if (cap->oap->op_type != OP_NOP) 3209 clearopbeep(cap->oap); 3210 3211 // Even if an operator was pending, we still want to jump tabs. 3212 goto_tabpage(current_tab); 3213 } 3214 3215 /* 3216 * Selected item in tab line menu. 3217 */ 3218 static void 3219 nv_tabmenu(cmdarg_T *cap) 3220 { 3221 if (cap->oap->op_type != OP_NOP) 3222 clearopbeep(cap->oap); 3223 3224 // Even if an operator was pending, we still want to jump tabs. 3225 handle_tabmenu(); 3226 } 3227 3228 /* 3229 * Handle selecting an item of the GUI tab line menu. 3230 * Used in Normal and Insert mode. 3231 */ 3232 void 3233 handle_tabmenu(void) 3234 { 3235 switch (current_tabmenu) 3236 { 3237 case TABLINE_MENU_CLOSE: 3238 if (current_tab == 0) 3239 do_cmdline_cmd((char_u *)"tabclose"); 3240 else 3241 { 3242 vim_snprintf((char *)IObuff, IOSIZE, "tabclose %d", 3243 current_tab); 3244 do_cmdline_cmd(IObuff); 3245 } 3246 break; 3247 3248 case TABLINE_MENU_NEW: 3249 if (current_tab == 0) 3250 do_cmdline_cmd((char_u *)"$tabnew"); 3251 else 3252 { 3253 vim_snprintf((char *)IObuff, IOSIZE, "%dtabnew", 3254 current_tab - 1); 3255 do_cmdline_cmd(IObuff); 3256 } 3257 break; 3258 3259 case TABLINE_MENU_OPEN: 3260 if (current_tab == 0) 3261 do_cmdline_cmd((char_u *)"browse $tabnew"); 3262 else 3263 { 3264 vim_snprintf((char *)IObuff, IOSIZE, "browse %dtabnew", 3265 current_tab - 1); 3266 do_cmdline_cmd(IObuff); 3267 } 3268 break; 3269 } 3270 } 3271 #endif 3272 3273 /* 3274 * "Q" command. 3275 */ 3276 static void 3277 nv_exmode(cmdarg_T *cap) 3278 { 3279 /* 3280 * Ignore 'Q' in Visual mode, just give a beep. 3281 */ 3282 if (VIsual_active) 3283 vim_beep(BO_EX); 3284 else if (!checkclearop(cap->oap)) 3285 do_exmode(FALSE); 3286 } 3287 3288 /* 3289 * Handle a ":" command. 3290 */ 3291 static void 3292 nv_colon(cmdarg_T *cap) 3293 { 3294 int old_p_im; 3295 int cmd_result; 3296 3297 if (VIsual_active) 3298 nv_operator(cap); 3299 else 3300 { 3301 if (cap->oap->op_type != OP_NOP) 3302 { 3303 // Using ":" as a movement is characterwise exclusive. 3304 cap->oap->motion_type = MCHAR; 3305 cap->oap->inclusive = FALSE; 3306 } 3307 else if (cap->count0) 3308 { 3309 // translate "count:" into ":.,.+(count - 1)" 3310 stuffcharReadbuff('.'); 3311 if (cap->count0 > 1) 3312 { 3313 stuffReadbuff((char_u *)",.+"); 3314 stuffnumReadbuff((long)cap->count0 - 1L); 3315 } 3316 } 3317 3318 // When typing, don't type below an old message 3319 if (KeyTyped) 3320 compute_cmdrow(); 3321 3322 old_p_im = p_im; 3323 3324 // get a command line and execute it 3325 cmd_result = do_cmdline(NULL, getexline, NULL, 3326 cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0); 3327 3328 // If 'insertmode' changed, enter or exit Insert mode 3329 if (p_im != old_p_im) 3330 { 3331 if (p_im) 3332 restart_edit = 'i'; 3333 else 3334 restart_edit = 0; 3335 } 3336 3337 if (cmd_result == FAIL) 3338 // The Ex command failed, do not execute the operator. 3339 clearop(cap->oap); 3340 else if (cap->oap->op_type != OP_NOP 3341 && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count 3342 || cap->oap->start.col > 3343 (colnr_T)STRLEN(ml_get(cap->oap->start.lnum)) 3344 || did_emsg 3345 )) 3346 // The start of the operator has become invalid by the Ex command. 3347 clearopbeep(cap->oap); 3348 } 3349 } 3350 3351 /* 3352 * Handle CTRL-G command. 3353 */ 3354 static void 3355 nv_ctrlg(cmdarg_T *cap) 3356 { 3357 if (VIsual_active) // toggle Selection/Visual mode 3358 { 3359 VIsual_select = !VIsual_select; 3360 showmode(); 3361 } 3362 else if (!checkclearop(cap->oap)) 3363 // print full name if count given or :cd used 3364 fileinfo((int)cap->count0, FALSE, TRUE); 3365 } 3366 3367 /* 3368 * Handle CTRL-H <Backspace> command. 3369 */ 3370 static void 3371 nv_ctrlh(cmdarg_T *cap) 3372 { 3373 if (VIsual_active && VIsual_select) 3374 { 3375 cap->cmdchar = 'x'; // BS key behaves like 'x' in Select mode 3376 v_visop(cap); 3377 } 3378 else 3379 nv_left(cap); 3380 } 3381 3382 /* 3383 * CTRL-L: clear screen and redraw. 3384 */ 3385 static void 3386 nv_clear(cmdarg_T *cap) 3387 { 3388 if (!checkclearop(cap->oap)) 3389 { 3390 #ifdef FEAT_SYN_HL 3391 // Clear all syntax states to force resyncing. 3392 syn_stack_free_all(curwin->w_s); 3393 # ifdef FEAT_RELTIME 3394 { 3395 win_T *wp; 3396 3397 FOR_ALL_WINDOWS(wp) 3398 wp->w_s->b_syn_slow = FALSE; 3399 } 3400 # endif 3401 #endif 3402 redraw_later(CLEAR); 3403 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3404 # ifdef VIMDLL 3405 if (!gui.in_use) 3406 # endif 3407 resize_console_buf(); 3408 #endif 3409 } 3410 } 3411 3412 /* 3413 * CTRL-O: In Select mode: switch to Visual mode for one command. 3414 * Otherwise: Go to older pcmark. 3415 */ 3416 static void 3417 nv_ctrlo(cmdarg_T *cap) 3418 { 3419 if (VIsual_active && VIsual_select) 3420 { 3421 VIsual_select = FALSE; 3422 showmode(); 3423 restart_VIsual_select = 2; // restart Select mode later 3424 } 3425 else 3426 { 3427 cap->count1 = -cap->count1; 3428 nv_pcmark(cap); 3429 } 3430 } 3431 3432 /* 3433 * CTRL-^ command, short for ":e #". Works even when the alternate buffer is 3434 * not named. 3435 */ 3436 static void 3437 nv_hat(cmdarg_T *cap) 3438 { 3439 if (!checkclearopq(cap->oap)) 3440 (void)buflist_getfile((int)cap->count0, (linenr_T)0, 3441 GETF_SETMARK|GETF_ALT, FALSE); 3442 } 3443 3444 /* 3445 * "Z" commands. 3446 */ 3447 static void 3448 nv_Zet(cmdarg_T *cap) 3449 { 3450 if (!checkclearopq(cap->oap)) 3451 { 3452 switch (cap->nchar) 3453 { 3454 // "ZZ": equivalent to ":x". 3455 case 'Z': do_cmdline_cmd((char_u *)"x"); 3456 break; 3457 3458 // "ZQ": equivalent to ":q!" (Elvis compatible). 3459 case 'Q': do_cmdline_cmd((char_u *)"q!"); 3460 break; 3461 3462 default: clearopbeep(cap->oap); 3463 } 3464 } 3465 } 3466 3467 /* 3468 * Call nv_ident() as if "c1" was used, with "c2" as next character. 3469 */ 3470 void 3471 do_nv_ident(int c1, int c2) 3472 { 3473 oparg_T oa; 3474 cmdarg_T ca; 3475 3476 clear_oparg(&oa); 3477 CLEAR_FIELD(ca); 3478 ca.oap = &oa; 3479 ca.cmdchar = c1; 3480 ca.nchar = c2; 3481 nv_ident(&ca); 3482 } 3483 3484 /* 3485 * Handle the commands that use the word under the cursor. 3486 * [g] CTRL-] :ta to current identifier 3487 * [g] 'K' run program for current identifier 3488 * [g] '*' / to current identifier or string 3489 * [g] '#' ? to current identifier or string 3490 * g ']' :tselect for current identifier 3491 */ 3492 static void 3493 nv_ident(cmdarg_T *cap) 3494 { 3495 char_u *ptr = NULL; 3496 char_u *buf; 3497 unsigned buflen; 3498 char_u *newbuf; 3499 char_u *p; 3500 char_u *kp; // value of 'keywordprg' 3501 int kp_help; // 'keywordprg' is ":he" 3502 int kp_ex; // 'keywordprg' starts with ":" 3503 int n = 0; // init for GCC 3504 int cmdchar; 3505 int g_cmd; // "g" command 3506 int tag_cmd = FALSE; 3507 char_u *aux_ptr; 3508 int isman; 3509 int isman_s; 3510 3511 if (cap->cmdchar == 'g') // "g*", "g#", "g]" and "gCTRL-]" 3512 { 3513 cmdchar = cap->nchar; 3514 g_cmd = TRUE; 3515 } 3516 else 3517 { 3518 cmdchar = cap->cmdchar; 3519 g_cmd = FALSE; 3520 } 3521 3522 if (cmdchar == POUND) // the pound sign, '#' for English keyboards 3523 cmdchar = '#'; 3524 3525 /* 3526 * The "]", "CTRL-]" and "K" commands accept an argument in Visual mode. 3527 */ 3528 if (cmdchar == ']' || cmdchar == Ctrl_RSB || cmdchar == 'K') 3529 { 3530 if (VIsual_active && get_visual_text(cap, &ptr, &n) == FAIL) 3531 return; 3532 if (checkclearopq(cap->oap)) 3533 return; 3534 } 3535 3536 if (ptr == NULL && (n = find_ident_under_cursor(&ptr, 3537 (cmdchar == '*' || cmdchar == '#') 3538 ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0) 3539 { 3540 clearop(cap->oap); 3541 return; 3542 } 3543 3544 // Allocate buffer to put the command in. Inserting backslashes can 3545 // double the length of the word. p_kp / curbuf->b_p_kp could be added 3546 // and some numbers. 3547 kp = (*curbuf->b_p_kp == NUL ? p_kp : curbuf->b_p_kp); 3548 kp_help = (*kp == NUL || STRCMP(kp, ":he") == 0 3549 || STRCMP(kp, ":help") == 0); 3550 if (kp_help && *skipwhite(ptr) == NUL) 3551 { 3552 emsg(_(e_noident)); // found white space only 3553 return; 3554 } 3555 kp_ex = (*kp == ':'); 3556 buflen = (unsigned)(n * 2 + 30 + STRLEN(kp)); 3557 buf = alloc(buflen); 3558 if (buf == NULL) 3559 return; 3560 buf[0] = NUL; 3561 3562 switch (cmdchar) 3563 { 3564 case '*': 3565 case '#': 3566 /* 3567 * Put cursor at start of word, makes search skip the word 3568 * under the cursor. 3569 * Call setpcmark() first, so "*``" puts the cursor back where 3570 * it was. 3571 */ 3572 setpcmark(); 3573 curwin->w_cursor.col = (colnr_T) (ptr - ml_get_curline()); 3574 3575 if (!g_cmd && vim_iswordp(ptr)) 3576 STRCPY(buf, "\\<"); 3577 no_smartcase = TRUE; // don't use 'smartcase' now 3578 break; 3579 3580 case 'K': 3581 if (kp_help) 3582 STRCPY(buf, "he! "); 3583 else if (kp_ex) 3584 { 3585 if (cap->count0 != 0) 3586 vim_snprintf((char *)buf, buflen, "%s %ld", 3587 kp, cap->count0); 3588 else 3589 STRCPY(buf, kp); 3590 STRCAT(buf, " "); 3591 } 3592 else 3593 { 3594 // An external command will probably use an argument starting 3595 // with "-" as an option. To avoid trouble we skip the "-". 3596 while (*ptr == '-' && n > 0) 3597 { 3598 ++ptr; 3599 --n; 3600 } 3601 if (n == 0) 3602 { 3603 emsg(_(e_noident)); // found dashes only 3604 vim_free(buf); 3605 return; 3606 } 3607 3608 // When a count is given, turn it into a range. Is this 3609 // really what we want? 3610 isman = (STRCMP(kp, "man") == 0); 3611 isman_s = (STRCMP(kp, "man -s") == 0); 3612 if (cap->count0 != 0 && !(isman || isman_s)) 3613 sprintf((char *)buf, ".,.+%ld", cap->count0 - 1); 3614 3615 STRCAT(buf, "! "); 3616 if (cap->count0 == 0 && isman_s) 3617 STRCAT(buf, "man"); 3618 else 3619 STRCAT(buf, kp); 3620 STRCAT(buf, " "); 3621 if (cap->count0 != 0 && (isman || isman_s)) 3622 { 3623 sprintf((char *)buf + STRLEN(buf), "%ld", cap->count0); 3624 STRCAT(buf, " "); 3625 } 3626 } 3627 break; 3628 3629 case ']': 3630 tag_cmd = TRUE; 3631 #ifdef FEAT_CSCOPE 3632 if (p_cst) 3633 STRCPY(buf, "cstag "); 3634 else 3635 #endif 3636 STRCPY(buf, "ts "); 3637 break; 3638 3639 default: 3640 tag_cmd = TRUE; 3641 if (curbuf->b_help) 3642 STRCPY(buf, "he! "); 3643 else 3644 { 3645 if (g_cmd) 3646 STRCPY(buf, "tj "); 3647 else if (cap->count0 == 0) 3648 STRCPY(buf, "ta "); 3649 else 3650 sprintf((char *)buf, ":%ldta ", cap->count0); 3651 } 3652 } 3653 3654 /* 3655 * Now grab the chars in the identifier 3656 */ 3657 if (cmdchar == 'K' && !kp_help) 3658 { 3659 ptr = vim_strnsave(ptr, n); 3660 if (kp_ex) 3661 // Escape the argument properly for an Ex command 3662 p = vim_strsave_fnameescape(ptr, FALSE); 3663 else 3664 // Escape the argument properly for a shell command 3665 p = vim_strsave_shellescape(ptr, TRUE, TRUE); 3666 vim_free(ptr); 3667 if (p == NULL) 3668 { 3669 vim_free(buf); 3670 return; 3671 } 3672 newbuf = vim_realloc(buf, STRLEN(buf) + STRLEN(p) + 1); 3673 if (newbuf == NULL) 3674 { 3675 vim_free(buf); 3676 vim_free(p); 3677 return; 3678 } 3679 buf = newbuf; 3680 STRCAT(buf, p); 3681 vim_free(p); 3682 } 3683 else 3684 { 3685 if (cmdchar == '*') 3686 aux_ptr = (char_u *)(p_magic ? "/.*~[^$\\" : "/^$\\"); 3687 else if (cmdchar == '#') 3688 aux_ptr = (char_u *)(p_magic ? "/?.*~[^$\\" : "/?^$\\"); 3689 else if (tag_cmd) 3690 { 3691 if (curbuf->b_help) 3692 // ":help" handles unescaped argument 3693 aux_ptr = (char_u *)""; 3694 else 3695 aux_ptr = (char_u *)"\\|\"\n["; 3696 } 3697 else 3698 aux_ptr = (char_u *)"\\|\"\n*?["; 3699 3700 p = buf + STRLEN(buf); 3701 while (n-- > 0) 3702 { 3703 // put a backslash before \ and some others 3704 if (vim_strchr(aux_ptr, *ptr) != NULL) 3705 *p++ = '\\'; 3706 // When current byte is a part of multibyte character, copy all 3707 // bytes of that character. 3708 if (has_mbyte) 3709 { 3710 int i; 3711 int len = (*mb_ptr2len)(ptr) - 1; 3712 3713 for (i = 0; i < len && n >= 1; ++i, --n) 3714 *p++ = *ptr++; 3715 } 3716 *p++ = *ptr++; 3717 } 3718 *p = NUL; 3719 } 3720 3721 /* 3722 * Execute the command. 3723 */ 3724 if (cmdchar == '*' || cmdchar == '#') 3725 { 3726 if (!g_cmd && (has_mbyte 3727 ? vim_iswordp(mb_prevptr(ml_get_curline(), ptr)) 3728 : vim_iswordc(ptr[-1]))) 3729 STRCAT(buf, "\\>"); 3730 3731 // put pattern in search history 3732 init_history(); 3733 add_to_history(HIST_SEARCH, buf, TRUE, NUL); 3734 3735 (void)normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0, NULL); 3736 } 3737 else 3738 { 3739 g_tag_at_cursor = TRUE; 3740 do_cmdline_cmd(buf); 3741 g_tag_at_cursor = FALSE; 3742 } 3743 3744 vim_free(buf); 3745 } 3746 3747 /* 3748 * Get visually selected text, within one line only. 3749 * Returns FAIL if more than one line selected. 3750 */ 3751 int 3752 get_visual_text( 3753 cmdarg_T *cap, 3754 char_u **pp, // return: start of selected text 3755 int *lenp) // return: length of selected text 3756 { 3757 if (VIsual_mode != 'V') 3758 unadjust_for_sel(); 3759 if (VIsual.lnum != curwin->w_cursor.lnum) 3760 { 3761 if (cap != NULL) 3762 clearopbeep(cap->oap); 3763 return FAIL; 3764 } 3765 if (VIsual_mode == 'V') 3766 { 3767 *pp = ml_get_curline(); 3768 *lenp = (int)STRLEN(*pp); 3769 } 3770 else 3771 { 3772 if (LT_POS(curwin->w_cursor, VIsual)) 3773 { 3774 *pp = ml_get_pos(&curwin->w_cursor); 3775 *lenp = VIsual.col - curwin->w_cursor.col + 1; 3776 } 3777 else 3778 { 3779 *pp = ml_get_pos(&VIsual); 3780 *lenp = curwin->w_cursor.col - VIsual.col + 1; 3781 } 3782 if (has_mbyte) 3783 // Correct the length to include the whole last character. 3784 *lenp += (*mb_ptr2len)(*pp + (*lenp - 1)) - 1; 3785 } 3786 reset_VIsual_and_resel(); 3787 return OK; 3788 } 3789 3790 /* 3791 * CTRL-T: backwards in tag stack 3792 */ 3793 static void 3794 nv_tagpop(cmdarg_T *cap) 3795 { 3796 if (!checkclearopq(cap->oap)) 3797 do_tag((char_u *)"", DT_POP, (int)cap->count1, FALSE, TRUE); 3798 } 3799 3800 /* 3801 * Handle scrolling command 'H', 'L' and 'M'. 3802 */ 3803 static void 3804 nv_scroll(cmdarg_T *cap) 3805 { 3806 int used = 0; 3807 long n; 3808 #ifdef FEAT_FOLDING 3809 linenr_T lnum; 3810 #endif 3811 int half; 3812 3813 cap->oap->motion_type = MLINE; 3814 setpcmark(); 3815 3816 if (cap->cmdchar == 'L') 3817 { 3818 validate_botline(); // make sure curwin->w_botline is valid 3819 curwin->w_cursor.lnum = curwin->w_botline - 1; 3820 if (cap->count1 - 1 >= curwin->w_cursor.lnum) 3821 curwin->w_cursor.lnum = 1; 3822 else 3823 { 3824 #ifdef FEAT_FOLDING 3825 if (hasAnyFolding(curwin)) 3826 { 3827 // Count a fold for one screen line. 3828 for (n = cap->count1 - 1; n > 0 3829 && curwin->w_cursor.lnum > curwin->w_topline; --n) 3830 { 3831 (void)hasFolding(curwin->w_cursor.lnum, 3832 &curwin->w_cursor.lnum, NULL); 3833 --curwin->w_cursor.lnum; 3834 } 3835 } 3836 else 3837 #endif 3838 curwin->w_cursor.lnum -= cap->count1 - 1; 3839 } 3840 } 3841 else 3842 { 3843 if (cap->cmdchar == 'M') 3844 { 3845 #ifdef FEAT_DIFF 3846 // Don't count filler lines above the window. 3847 used -= diff_check_fill(curwin, curwin->w_topline) 3848 - curwin->w_topfill; 3849 #endif 3850 validate_botline(); // make sure w_empty_rows is valid 3851 half = (curwin->w_height - curwin->w_empty_rows + 1) / 2; 3852 for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n) 3853 { 3854 #ifdef FEAT_DIFF 3855 // Count half he number of filler lines to be "below this 3856 // line" and half to be "above the next line". 3857 if (n > 0 && used + diff_check_fill(curwin, curwin->w_topline 3858 + n) / 2 >= half) 3859 { 3860 --n; 3861 break; 3862 } 3863 #endif 3864 used += plines(curwin->w_topline + n); 3865 if (used >= half) 3866 break; 3867 #ifdef FEAT_FOLDING 3868 if (hasFolding(curwin->w_topline + n, NULL, &lnum)) 3869 n = lnum - curwin->w_topline; 3870 #endif 3871 } 3872 if (n > 0 && used > curwin->w_height) 3873 --n; 3874 } 3875 else // (cap->cmdchar == 'H') 3876 { 3877 n = cap->count1 - 1; 3878 #ifdef FEAT_FOLDING 3879 if (hasAnyFolding(curwin)) 3880 { 3881 // Count a fold for one screen line. 3882 lnum = curwin->w_topline; 3883 while (n-- > 0 && lnum < curwin->w_botline - 1) 3884 { 3885 (void)hasFolding(lnum, NULL, &lnum); 3886 ++lnum; 3887 } 3888 n = lnum - curwin->w_topline; 3889 } 3890 #endif 3891 } 3892 curwin->w_cursor.lnum = curwin->w_topline + n; 3893 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 3894 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 3895 } 3896 3897 // Correct for 'so', except when an operator is pending. 3898 if (cap->oap->op_type == OP_NOP) 3899 cursor_correct(); 3900 beginline(BL_SOL | BL_FIX); 3901 } 3902 3903 /* 3904 * Cursor right commands. 3905 */ 3906 static void 3907 nv_right(cmdarg_T *cap) 3908 { 3909 long n; 3910 int past_line; 3911 3912 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) 3913 { 3914 // <C-Right> and <S-Right> move a word or WORD right 3915 if (mod_mask & MOD_MASK_CTRL) 3916 cap->arg = TRUE; 3917 nv_wordcmd(cap); 3918 return; 3919 } 3920 3921 cap->oap->motion_type = MCHAR; 3922 cap->oap->inclusive = FALSE; 3923 past_line = (VIsual_active && *p_sel != 'o'); 3924 3925 /* 3926 * In virtual edit mode, there's no such thing as "past_line", as lines 3927 * are (theoretically) infinitely long. 3928 */ 3929 if (virtual_active()) 3930 past_line = 0; 3931 3932 for (n = cap->count1; n > 0; --n) 3933 { 3934 if ((!past_line && oneright() == FAIL) 3935 || (past_line && *ml_get_cursor() == NUL) 3936 ) 3937 { 3938 /* 3939 * <Space> wraps to next line if 'whichwrap' has 's'. 3940 * 'l' wraps to next line if 'whichwrap' has 'l'. 3941 * CURS_RIGHT wraps to next line if 'whichwrap' has '>'. 3942 */ 3943 if ( ((cap->cmdchar == ' ' 3944 && vim_strchr(p_ww, 's') != NULL) 3945 || (cap->cmdchar == 'l' 3946 && vim_strchr(p_ww, 'l') != NULL) 3947 || (cap->cmdchar == K_RIGHT 3948 && vim_strchr(p_ww, '>') != NULL)) 3949 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 3950 { 3951 // When deleting we also count the NL as a character. 3952 // Set cap->oap->inclusive when last char in the line is 3953 // included, move to next line after that 3954 if ( cap->oap->op_type != OP_NOP 3955 && !cap->oap->inclusive 3956 && !LINEEMPTY(curwin->w_cursor.lnum)) 3957 cap->oap->inclusive = TRUE; 3958 else 3959 { 3960 ++curwin->w_cursor.lnum; 3961 curwin->w_cursor.col = 0; 3962 curwin->w_cursor.coladd = 0; 3963 curwin->w_set_curswant = TRUE; 3964 cap->oap->inclusive = FALSE; 3965 } 3966 continue; 3967 } 3968 if (cap->oap->op_type == OP_NOP) 3969 { 3970 // Only beep and flush if not moved at all 3971 if (n == cap->count1) 3972 beep_flush(); 3973 } 3974 else 3975 { 3976 if (!LINEEMPTY(curwin->w_cursor.lnum)) 3977 cap->oap->inclusive = TRUE; 3978 } 3979 break; 3980 } 3981 else if (past_line) 3982 { 3983 curwin->w_set_curswant = TRUE; 3984 if (virtual_active()) 3985 oneright(); 3986 else 3987 { 3988 if (has_mbyte) 3989 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor()); 3990 else 3991 ++curwin->w_cursor.col; 3992 } 3993 } 3994 } 3995 #ifdef FEAT_FOLDING 3996 if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped 3997 && cap->oap->op_type == OP_NOP) 3998 foldOpenCursor(); 3999 #endif 4000 } 4001 4002 /* 4003 * Cursor left commands. 4004 * 4005 * Returns TRUE when operator end should not be adjusted. 4006 */ 4007 static void 4008 nv_left(cmdarg_T *cap) 4009 { 4010 long n; 4011 4012 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) 4013 { 4014 // <C-Left> and <S-Left> move a word or WORD left 4015 if (mod_mask & MOD_MASK_CTRL) 4016 cap->arg = 1; 4017 nv_bck_word(cap); 4018 return; 4019 } 4020 4021 cap->oap->motion_type = MCHAR; 4022 cap->oap->inclusive = FALSE; 4023 for (n = cap->count1; n > 0; --n) 4024 { 4025 if (oneleft() == FAIL) 4026 { 4027 // <BS> and <Del> wrap to previous line if 'whichwrap' has 'b'. 4028 // 'h' wraps to previous line if 'whichwrap' has 'h'. 4029 // CURS_LEFT wraps to previous line if 'whichwrap' has '<'. 4030 if ( (((cap->cmdchar == K_BS 4031 || cap->cmdchar == Ctrl_H) 4032 && vim_strchr(p_ww, 'b') != NULL) 4033 || (cap->cmdchar == 'h' 4034 && vim_strchr(p_ww, 'h') != NULL) 4035 || (cap->cmdchar == K_LEFT 4036 && vim_strchr(p_ww, '<') != NULL)) 4037 && curwin->w_cursor.lnum > 1) 4038 { 4039 --(curwin->w_cursor.lnum); 4040 coladvance((colnr_T)MAXCOL); 4041 curwin->w_set_curswant = TRUE; 4042 4043 // When the NL before the first char has to be deleted we 4044 // put the cursor on the NUL after the previous line. 4045 // This is a very special case, be careful! 4046 // Don't adjust op_end now, otherwise it won't work. 4047 if ( (cap->oap->op_type == OP_DELETE 4048 || cap->oap->op_type == OP_CHANGE) 4049 && !LINEEMPTY(curwin->w_cursor.lnum)) 4050 { 4051 char_u *cp = ml_get_cursor(); 4052 4053 if (*cp != NUL) 4054 { 4055 if (has_mbyte) 4056 curwin->w_cursor.col += (*mb_ptr2len)(cp); 4057 else 4058 ++curwin->w_cursor.col; 4059 } 4060 cap->retval |= CA_NO_ADJ_OP_END; 4061 } 4062 continue; 4063 } 4064 // Only beep and flush if not moved at all 4065 else if (cap->oap->op_type == OP_NOP && n == cap->count1) 4066 beep_flush(); 4067 break; 4068 } 4069 } 4070 #ifdef FEAT_FOLDING 4071 if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped 4072 && cap->oap->op_type == OP_NOP) 4073 foldOpenCursor(); 4074 #endif 4075 } 4076 4077 /* 4078 * Cursor up commands. 4079 * cap->arg is TRUE for "-": Move cursor to first non-blank. 4080 */ 4081 static void 4082 nv_up(cmdarg_T *cap) 4083 { 4084 if (mod_mask & MOD_MASK_SHIFT) 4085 { 4086 // <S-Up> is page up 4087 cap->arg = BACKWARD; 4088 nv_page(cap); 4089 } 4090 else 4091 { 4092 cap->oap->motion_type = MLINE; 4093 if (cursor_up(cap->count1, cap->oap->op_type == OP_NOP) == FAIL) 4094 clearopbeep(cap->oap); 4095 else if (cap->arg) 4096 beginline(BL_WHITE | BL_FIX); 4097 } 4098 } 4099 4100 /* 4101 * Cursor down commands. 4102 * cap->arg is TRUE for CR and "+": Move cursor to first non-blank. 4103 */ 4104 static void 4105 nv_down(cmdarg_T *cap) 4106 { 4107 if (mod_mask & MOD_MASK_SHIFT) 4108 { 4109 // <S-Down> is page down 4110 cap->arg = FORWARD; 4111 nv_page(cap); 4112 } 4113 #if defined(FEAT_QUICKFIX) 4114 // Quickfix window only: view the result under the cursor. 4115 else if (bt_quickfix(curbuf) && cap->cmdchar == CAR) 4116 qf_view_result(FALSE); 4117 #endif 4118 else 4119 { 4120 #ifdef FEAT_CMDWIN 4121 // In the cmdline window a <CR> executes the command. 4122 if (cmdwin_type != 0 && cap->cmdchar == CAR) 4123 cmdwin_result = CAR; 4124 else 4125 #endif 4126 #ifdef FEAT_JOB_CHANNEL 4127 // In a prompt buffer a <CR> in the last line invokes the callback. 4128 if (bt_prompt(curbuf) && cap->cmdchar == CAR 4129 && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) 4130 { 4131 invoke_prompt_callback(); 4132 if (restart_edit == 0) 4133 restart_edit = 'a'; 4134 } 4135 else 4136 #endif 4137 { 4138 cap->oap->motion_type = MLINE; 4139 if (cursor_down(cap->count1, cap->oap->op_type == OP_NOP) == FAIL) 4140 clearopbeep(cap->oap); 4141 else if (cap->arg) 4142 beginline(BL_WHITE | BL_FIX); 4143 } 4144 } 4145 } 4146 4147 #ifdef FEAT_SEARCHPATH 4148 /* 4149 * Grab the file name under the cursor and edit it. 4150 */ 4151 static void 4152 nv_gotofile(cmdarg_T *cap) 4153 { 4154 char_u *ptr; 4155 linenr_T lnum = -1; 4156 4157 if (text_locked()) 4158 { 4159 clearopbeep(cap->oap); 4160 text_locked_msg(); 4161 return; 4162 } 4163 if (curbuf_locked()) 4164 { 4165 clearop(cap->oap); 4166 return; 4167 } 4168 #ifdef FEAT_PROP_POPUP 4169 if (ERROR_IF_TERM_POPUP_WINDOW) 4170 return; 4171 #endif 4172 4173 ptr = grab_file_name(cap->count1, &lnum); 4174 4175 if (ptr != NULL) 4176 { 4177 // do autowrite if necessary 4178 if (curbufIsChanged() && curbuf->b_nwindows <= 1 && !buf_hide(curbuf)) 4179 (void)autowrite(curbuf, FALSE); 4180 setpcmark(); 4181 if (do_ecmd(0, ptr, NULL, NULL, ECMD_LAST, 4182 buf_hide(curbuf) ? ECMD_HIDE : 0, curwin) == OK 4183 && cap->nchar == 'F' && lnum >= 0) 4184 { 4185 curwin->w_cursor.lnum = lnum; 4186 check_cursor_lnum(); 4187 beginline(BL_SOL | BL_FIX); 4188 } 4189 vim_free(ptr); 4190 } 4191 else 4192 clearop(cap->oap); 4193 } 4194 #endif 4195 4196 /* 4197 * <End> command: to end of current line or last line. 4198 */ 4199 static void 4200 nv_end(cmdarg_T *cap) 4201 { 4202 if (cap->arg || (mod_mask & MOD_MASK_CTRL)) // CTRL-END = goto last line 4203 { 4204 cap->arg = TRUE; 4205 nv_goto(cap); 4206 cap->count1 = 1; // to end of current line 4207 } 4208 nv_dollar(cap); 4209 } 4210 4211 /* 4212 * Handle the "$" command. 4213 */ 4214 static void 4215 nv_dollar(cmdarg_T *cap) 4216 { 4217 cap->oap->motion_type = MCHAR; 4218 cap->oap->inclusive = TRUE; 4219 // In virtual mode when off the edge of a line and an operator 4220 // is pending (whew!) keep the cursor where it is. 4221 // Otherwise, send it to the end of the line. 4222 if (!virtual_active() || gchar_cursor() != NUL 4223 || cap->oap->op_type == OP_NOP) 4224 curwin->w_curswant = MAXCOL; // so we stay at the end 4225 if (cursor_down((long)(cap->count1 - 1), 4226 cap->oap->op_type == OP_NOP) == FAIL) 4227 clearopbeep(cap->oap); 4228 #ifdef FEAT_FOLDING 4229 else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) 4230 foldOpenCursor(); 4231 #endif 4232 } 4233 4234 /* 4235 * Implementation of '?' and '/' commands. 4236 * If cap->arg is TRUE don't set PC mark. 4237 */ 4238 static void 4239 nv_search(cmdarg_T *cap) 4240 { 4241 oparg_T *oap = cap->oap; 4242 pos_T save_cursor = curwin->w_cursor; 4243 4244 if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13) 4245 { 4246 // Translate "g??" to "g?g?" 4247 cap->cmdchar = 'g'; 4248 cap->nchar = '?'; 4249 nv_operator(cap); 4250 return; 4251 } 4252 4253 // When using 'incsearch' the cursor may be moved to set a different search 4254 // start position. 4255 cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0, TRUE); 4256 4257 if (cap->searchbuf == NULL) 4258 { 4259 clearop(oap); 4260 return; 4261 } 4262 4263 (void)normal_search(cap, cap->cmdchar, cap->searchbuf, 4264 (cap->arg || !EQUAL_POS(save_cursor, curwin->w_cursor)) 4265 ? 0 : SEARCH_MARK, NULL); 4266 } 4267 4268 /* 4269 * Handle "N" and "n" commands. 4270 * cap->arg is SEARCH_REV for "N", 0 for "n". 4271 */ 4272 static void 4273 nv_next(cmdarg_T *cap) 4274 { 4275 pos_T old = curwin->w_cursor; 4276 int wrapped = FALSE; 4277 int i = normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, &wrapped); 4278 4279 if (i == 1 && !wrapped && EQUAL_POS(old, curwin->w_cursor)) 4280 { 4281 // Avoid getting stuck on the current cursor position, which can 4282 // happen when an offset is given and the cursor is on the last char 4283 // in the buffer: Repeat with count + 1. 4284 cap->count1 += 1; 4285 (void)normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, NULL); 4286 cap->count1 -= 1; 4287 } 4288 } 4289 4290 /* 4291 * Search for "pat" in direction "dir" ('/' or '?', 0 for repeat). 4292 * Uses only cap->count1 and cap->oap from "cap". 4293 * Return 0 for failure, 1 for found, 2 for found and line offset added. 4294 */ 4295 static int 4296 normal_search( 4297 cmdarg_T *cap, 4298 int dir, 4299 char_u *pat, 4300 int opt, // extra flags for do_search() 4301 int *wrapped) 4302 { 4303 int i; 4304 searchit_arg_T sia; 4305 4306 cap->oap->motion_type = MCHAR; 4307 cap->oap->inclusive = FALSE; 4308 cap->oap->use_reg_one = TRUE; 4309 curwin->w_set_curswant = TRUE; 4310 4311 CLEAR_FIELD(sia); 4312 i = do_search(cap->oap, dir, dir, pat, cap->count1, 4313 opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia); 4314 if (wrapped != NULL) 4315 *wrapped = sia.sa_wrapped; 4316 if (i == 0) 4317 clearop(cap->oap); 4318 else 4319 { 4320 if (i == 2) 4321 cap->oap->motion_type = MLINE; 4322 curwin->w_cursor.coladd = 0; 4323 #ifdef FEAT_FOLDING 4324 if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) 4325 foldOpenCursor(); 4326 #endif 4327 } 4328 4329 // "/$" will put the cursor after the end of the line, may need to 4330 // correct that here 4331 check_cursor(); 4332 return i; 4333 } 4334 4335 /* 4336 * Character search commands. 4337 * cap->arg is BACKWARD for 'F' and 'T', FORWARD for 'f' and 't', TRUE for 4338 * ',' and FALSE for ';'. 4339 * cap->nchar is NUL for ',' and ';' (repeat the search) 4340 */ 4341 static void 4342 nv_csearch(cmdarg_T *cap) 4343 { 4344 int t_cmd; 4345 4346 if (cap->cmdchar == 't' || cap->cmdchar == 'T') 4347 t_cmd = TRUE; 4348 else 4349 t_cmd = FALSE; 4350 4351 cap->oap->motion_type = MCHAR; 4352 if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == FAIL) 4353 clearopbeep(cap->oap); 4354 else 4355 { 4356 curwin->w_set_curswant = TRUE; 4357 // Include a Tab for "tx" and for "dfx". 4358 if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD 4359 && (t_cmd || cap->oap->op_type != OP_NOP)) 4360 { 4361 colnr_T scol, ecol; 4362 4363 getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol); 4364 curwin->w_cursor.coladd = ecol - scol; 4365 } 4366 else 4367 curwin->w_cursor.coladd = 0; 4368 adjust_for_sel(cap); 4369 #ifdef FEAT_FOLDING 4370 if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) 4371 foldOpenCursor(); 4372 #endif 4373 } 4374 } 4375 4376 /* 4377 * "[" and "]" commands. 4378 * cap->arg is BACKWARD for "[" and FORWARD for "]". 4379 */ 4380 static void 4381 nv_brackets(cmdarg_T *cap) 4382 { 4383 pos_T new_pos = {0, 0, 0}; 4384 pos_T prev_pos; 4385 pos_T *pos = NULL; // init for GCC 4386 pos_T old_pos; // cursor position before command 4387 int flag; 4388 long n; 4389 int findc; 4390 int c; 4391 4392 cap->oap->motion_type = MCHAR; 4393 cap->oap->inclusive = FALSE; 4394 old_pos = curwin->w_cursor; 4395 curwin->w_cursor.coladd = 0; // TODO: don't do this for an error. 4396 4397 #ifdef FEAT_SEARCHPATH 4398 /* 4399 * "[f" or "]f" : Edit file under the cursor (same as "gf") 4400 */ 4401 if (cap->nchar == 'f') 4402 nv_gotofile(cap); 4403 else 4404 #endif 4405 4406 #ifdef FEAT_FIND_ID 4407 /* 4408 * Find the occurrence(s) of the identifier or define under cursor 4409 * in current and included files or jump to the first occurrence. 4410 * 4411 * search list jump 4412 * fwd bwd fwd bwd fwd bwd 4413 * identifier "]i" "[i" "]I" "[I" "]^I" "[^I" 4414 * define "]d" "[d" "]D" "[D" "]^D" "[^D" 4415 */ 4416 if (vim_strchr((char_u *) 4417 # ifdef EBCDIC 4418 "iI\005dD\067", 4419 # else 4420 "iI\011dD\004", 4421 # endif 4422 cap->nchar) != NULL) 4423 { 4424 char_u *ptr; 4425 int len; 4426 4427 if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) 4428 clearop(cap->oap); 4429 else 4430 { 4431 find_pattern_in_path(ptr, 0, len, TRUE, 4432 cap->count0 == 0 ? !isupper(cap->nchar) : FALSE, 4433 ((cap->nchar & 0xf) == ('d' & 0xf)) ? FIND_DEFINE : FIND_ANY, 4434 cap->count1, 4435 isupper(cap->nchar) ? ACTION_SHOW_ALL : 4436 islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO, 4437 cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : (linenr_T)1, 4438 (linenr_T)MAXLNUM); 4439 curwin->w_set_curswant = TRUE; 4440 } 4441 } 4442 else 4443 #endif 4444 4445 /* 4446 * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')' 4447 * "[#", "]#": go to start/end of Nth innermost #if..#endif construct. 4448 * "[/", "[*", "]/", "]*": go to Nth comment start/end. 4449 * "[m" or "]m" search for prev/next start of (Java) method. 4450 * "[M" or "]M" search for prev/next end of (Java) method. 4451 */ 4452 if ( (cap->cmdchar == '[' 4453 && vim_strchr((char_u *)"{(*/#mM", cap->nchar) != NULL) 4454 || (cap->cmdchar == ']' 4455 && vim_strchr((char_u *)"})*/#mM", cap->nchar) != NULL)) 4456 { 4457 if (cap->nchar == '*') 4458 cap->nchar = '/'; 4459 prev_pos.lnum = 0; 4460 if (cap->nchar == 'm' || cap->nchar == 'M') 4461 { 4462 if (cap->cmdchar == '[') 4463 findc = '{'; 4464 else 4465 findc = '}'; 4466 n = 9999; 4467 } 4468 else 4469 { 4470 findc = cap->nchar; 4471 n = cap->count1; 4472 } 4473 for ( ; n > 0; --n) 4474 { 4475 if ((pos = findmatchlimit(cap->oap, findc, 4476 (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL) 4477 { 4478 if (new_pos.lnum == 0) // nothing found 4479 { 4480 if (cap->nchar != 'm' && cap->nchar != 'M') 4481 clearopbeep(cap->oap); 4482 } 4483 else 4484 pos = &new_pos; // use last one found 4485 break; 4486 } 4487 prev_pos = new_pos; 4488 curwin->w_cursor = *pos; 4489 new_pos = *pos; 4490 } 4491 curwin->w_cursor = old_pos; 4492 4493 /* 4494 * Handle "[m", "]m", "[M" and "[M". The findmatchlimit() only 4495 * brought us to the match for "[m" and "]M" when inside a method. 4496 * Try finding the '{' or '}' we want to be at. 4497 * Also repeat for the given count. 4498 */ 4499 if (cap->nchar == 'm' || cap->nchar == 'M') 4500 { 4501 // norm is TRUE for "]M" and "[m" 4502 int norm = ((findc == '{') == (cap->nchar == 'm')); 4503 4504 n = cap->count1; 4505 // found a match: we were inside a method 4506 if (prev_pos.lnum != 0) 4507 { 4508 pos = &prev_pos; 4509 curwin->w_cursor = prev_pos; 4510 if (norm) 4511 --n; 4512 } 4513 else 4514 pos = NULL; 4515 while (n > 0) 4516 { 4517 for (;;) 4518 { 4519 if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0) 4520 { 4521 // if not found anything, that's an error 4522 if (pos == NULL) 4523 clearopbeep(cap->oap); 4524 n = 0; 4525 break; 4526 } 4527 c = gchar_cursor(); 4528 if (c == '{' || c == '}') 4529 { 4530 // Must have found end/start of class: use it. 4531 // Or found the place to be at. 4532 if ((c == findc && norm) || (n == 1 && !norm)) 4533 { 4534 new_pos = curwin->w_cursor; 4535 pos = &new_pos; 4536 n = 0; 4537 } 4538 // if no match found at all, we started outside of the 4539 // class and we're inside now. Just go on. 4540 else if (new_pos.lnum == 0) 4541 { 4542 new_pos = curwin->w_cursor; 4543 pos = &new_pos; 4544 } 4545 // found start/end of other method: go to match 4546 else if ((pos = findmatchlimit(cap->oap, findc, 4547 (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 4548 0)) == NULL) 4549 n = 0; 4550 else 4551 curwin->w_cursor = *pos; 4552 break; 4553 } 4554 } 4555 --n; 4556 } 4557 curwin->w_cursor = old_pos; 4558 if (pos == NULL && new_pos.lnum != 0) 4559 clearopbeep(cap->oap); 4560 } 4561 if (pos != NULL) 4562 { 4563 setpcmark(); 4564 curwin->w_cursor = *pos; 4565 curwin->w_set_curswant = TRUE; 4566 #ifdef FEAT_FOLDING 4567 if ((fdo_flags & FDO_BLOCK) && KeyTyped 4568 && cap->oap->op_type == OP_NOP) 4569 foldOpenCursor(); 4570 #endif 4571 } 4572 } 4573 4574 /* 4575 * "[[", "[]", "]]" and "][": move to start or end of function 4576 */ 4577 else if (cap->nchar == '[' || cap->nchar == ']') 4578 { 4579 if (cap->nchar == cap->cmdchar) // "]]" or "[[" 4580 flag = '{'; 4581 else 4582 flag = '}'; // "][" or "[]" 4583 4584 curwin->w_set_curswant = TRUE; 4585 /* 4586 * Imitate strange Vi behaviour: When using "]]" with an operator 4587 * we also stop at '}'. 4588 */ 4589 if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, flag, 4590 (cap->oap->op_type != OP_NOP 4591 && cap->arg == FORWARD && flag == '{'))) 4592 clearopbeep(cap->oap); 4593 else 4594 { 4595 if (cap->oap->op_type == OP_NOP) 4596 beginline(BL_WHITE | BL_FIX); 4597 #ifdef FEAT_FOLDING 4598 if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) 4599 foldOpenCursor(); 4600 #endif 4601 } 4602 } 4603 4604 /* 4605 * "[p", "[P", "]P" and "]p": put with indent adjustment 4606 */ 4607 else if (cap->nchar == 'p' || cap->nchar == 'P') 4608 { 4609 nv_put_opt(cap, TRUE); 4610 } 4611 4612 /* 4613 * "['", "[`", "]'" and "]`": jump to next mark 4614 */ 4615 else if (cap->nchar == '\'' || cap->nchar == '`') 4616 { 4617 pos = &curwin->w_cursor; 4618 for (n = cap->count1; n > 0; --n) 4619 { 4620 prev_pos = *pos; 4621 pos = getnextmark(pos, cap->cmdchar == '[' ? BACKWARD : FORWARD, 4622 cap->nchar == '\''); 4623 if (pos == NULL) 4624 break; 4625 } 4626 if (pos == NULL) 4627 pos = &prev_pos; 4628 nv_cursormark(cap, cap->nchar == '\'', pos); 4629 } 4630 4631 /* 4632 * [ or ] followed by a middle mouse click: put selected text with 4633 * indent adjustment. Any other button just does as usual. 4634 */ 4635 else if (cap->nchar >= K_RIGHTRELEASE && cap->nchar <= K_LEFTMOUSE) 4636 { 4637 (void)do_mouse(cap->oap, cap->nchar, 4638 (cap->cmdchar == ']') ? FORWARD : BACKWARD, 4639 cap->count1, PUT_FIXINDENT); 4640 } 4641 4642 #ifdef FEAT_FOLDING 4643 /* 4644 * "[z" and "]z": move to start or end of open fold. 4645 */ 4646 else if (cap->nchar == 'z') 4647 { 4648 if (foldMoveTo(FALSE, cap->cmdchar == ']' ? FORWARD : BACKWARD, 4649 cap->count1) == FAIL) 4650 clearopbeep(cap->oap); 4651 } 4652 #endif 4653 4654 #ifdef FEAT_DIFF 4655 /* 4656 * "[c" and "]c": move to next or previous diff-change. 4657 */ 4658 else if (cap->nchar == 'c') 4659 { 4660 if (diff_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD, 4661 cap->count1) == FAIL) 4662 clearopbeep(cap->oap); 4663 } 4664 #endif 4665 4666 #ifdef FEAT_SPELL 4667 /* 4668 * "[s", "[S", "]s" and "]S": move to next spell error. 4669 */ 4670 else if (cap->nchar == 's' || cap->nchar == 'S') 4671 { 4672 setpcmark(); 4673 for (n = 0; n < cap->count1; ++n) 4674 if (spell_move_to(curwin, cap->cmdchar == ']' ? FORWARD : BACKWARD, 4675 cap->nchar == 's' ? TRUE : FALSE, FALSE, NULL) == 0) 4676 { 4677 clearopbeep(cap->oap); 4678 break; 4679 } 4680 else 4681 curwin->w_set_curswant = TRUE; 4682 # ifdef FEAT_FOLDING 4683 if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) 4684 foldOpenCursor(); 4685 # endif 4686 } 4687 #endif 4688 4689 // Not a valid cap->nchar. 4690 else 4691 clearopbeep(cap->oap); 4692 } 4693 4694 /* 4695 * Handle Normal mode "%" command. 4696 */ 4697 static void 4698 nv_percent(cmdarg_T *cap) 4699 { 4700 pos_T *pos; 4701 #if defined(FEAT_FOLDING) 4702 linenr_T lnum = curwin->w_cursor.lnum; 4703 #endif 4704 4705 cap->oap->inclusive = TRUE; 4706 if (cap->count0) // {cnt}% : goto {cnt} percentage in file 4707 { 4708 if (cap->count0 > 100) 4709 clearopbeep(cap->oap); 4710 else 4711 { 4712 cap->oap->motion_type = MLINE; 4713 setpcmark(); 4714 // Round up, so CTRL-G will give same value. Watch out for a 4715 // large line count, the line number must not go negative! 4716 if (curbuf->b_ml.ml_line_count > 1000000) 4717 curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count + 99L) 4718 / 100L * cap->count0; 4719 else 4720 curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count * 4721 cap->count0 + 99L) / 100L; 4722 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 4723 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 4724 beginline(BL_SOL | BL_FIX); 4725 } 4726 } 4727 else // "%" : go to matching paren 4728 { 4729 cap->oap->motion_type = MCHAR; 4730 cap->oap->use_reg_one = TRUE; 4731 if ((pos = findmatch(cap->oap, NUL)) == NULL) 4732 clearopbeep(cap->oap); 4733 else 4734 { 4735 setpcmark(); 4736 curwin->w_cursor = *pos; 4737 curwin->w_set_curswant = TRUE; 4738 curwin->w_cursor.coladd = 0; 4739 adjust_for_sel(cap); 4740 } 4741 } 4742 #ifdef FEAT_FOLDING 4743 if (cap->oap->op_type == OP_NOP 4744 && lnum != curwin->w_cursor.lnum 4745 && (fdo_flags & FDO_PERCENT) 4746 && KeyTyped) 4747 foldOpenCursor(); 4748 #endif 4749 } 4750 4751 /* 4752 * Handle "(" and ")" commands. 4753 * cap->arg is BACKWARD for "(" and FORWARD for ")". 4754 */ 4755 static void 4756 nv_brace(cmdarg_T *cap) 4757 { 4758 cap->oap->motion_type = MCHAR; 4759 cap->oap->use_reg_one = TRUE; 4760 // The motion used to be inclusive for "(", but that is not what Vi does. 4761 cap->oap->inclusive = FALSE; 4762 curwin->w_set_curswant = TRUE; 4763 4764 if (findsent(cap->arg, cap->count1) == FAIL) 4765 clearopbeep(cap->oap); 4766 else 4767 { 4768 // Don't leave the cursor on the NUL past end of line. 4769 adjust_cursor(cap->oap); 4770 curwin->w_cursor.coladd = 0; 4771 #ifdef FEAT_FOLDING 4772 if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) 4773 foldOpenCursor(); 4774 #endif 4775 } 4776 } 4777 4778 /* 4779 * "m" command: Mark a position. 4780 */ 4781 static void 4782 nv_mark(cmdarg_T *cap) 4783 { 4784 if (!checkclearop(cap->oap)) 4785 { 4786 if (setmark(cap->nchar) == FAIL) 4787 clearopbeep(cap->oap); 4788 } 4789 } 4790 4791 /* 4792 * "{" and "}" commands. 4793 * cmd->arg is BACKWARD for "{" and FORWARD for "}". 4794 */ 4795 static void 4796 nv_findpar(cmdarg_T *cap) 4797 { 4798 cap->oap->motion_type = MCHAR; 4799 cap->oap->inclusive = FALSE; 4800 cap->oap->use_reg_one = TRUE; 4801 curwin->w_set_curswant = TRUE; 4802 if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, NUL, FALSE)) 4803 clearopbeep(cap->oap); 4804 else 4805 { 4806 curwin->w_cursor.coladd = 0; 4807 #ifdef FEAT_FOLDING 4808 if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) 4809 foldOpenCursor(); 4810 #endif 4811 } 4812 } 4813 4814 /* 4815 * "u" command: Undo or make lower case. 4816 */ 4817 static void 4818 nv_undo(cmdarg_T *cap) 4819 { 4820 if (cap->oap->op_type == OP_LOWER || VIsual_active) 4821 { 4822 // translate "<Visual>u" to "<Visual>gu" and "guu" to "gugu" 4823 cap->cmdchar = 'g'; 4824 cap->nchar = 'u'; 4825 nv_operator(cap); 4826 } 4827 else 4828 nv_kundo(cap); 4829 } 4830 4831 /* 4832 * <Undo> command. 4833 */ 4834 static void 4835 nv_kundo(cmdarg_T *cap) 4836 { 4837 if (!checkclearopq(cap->oap)) 4838 { 4839 #ifdef FEAT_JOB_CHANNEL 4840 if (bt_prompt(curbuf)) 4841 { 4842 clearopbeep(cap->oap); 4843 return; 4844 } 4845 #endif 4846 u_undo((int)cap->count1); 4847 curwin->w_set_curswant = TRUE; 4848 } 4849 } 4850 4851 /* 4852 * Handle the "r" command. 4853 */ 4854 static void 4855 nv_replace(cmdarg_T *cap) 4856 { 4857 char_u *ptr; 4858 int had_ctrl_v; 4859 long n; 4860 4861 if (checkclearop(cap->oap)) 4862 return; 4863 #ifdef FEAT_JOB_CHANNEL 4864 if (bt_prompt(curbuf) && !prompt_curpos_editable()) 4865 { 4866 clearopbeep(cap->oap); 4867 return; 4868 } 4869 #endif 4870 4871 // get another character 4872 if (cap->nchar == Ctrl_V) 4873 { 4874 had_ctrl_v = Ctrl_V; 4875 cap->nchar = get_literal(); 4876 // Don't redo a multibyte character with CTRL-V. 4877 if (cap->nchar > DEL) 4878 had_ctrl_v = NUL; 4879 } 4880 else 4881 had_ctrl_v = NUL; 4882 4883 // Abort if the character is a special key. 4884 if (IS_SPECIAL(cap->nchar)) 4885 { 4886 clearopbeep(cap->oap); 4887 return; 4888 } 4889 4890 // Visual mode "r" 4891 if (VIsual_active) 4892 { 4893 if (got_int) 4894 reset_VIsual(); 4895 if (had_ctrl_v) 4896 { 4897 // Use a special (negative) number to make a difference between a 4898 // literal CR or NL and a line break. 4899 if (cap->nchar == CAR) 4900 cap->nchar = REPLACE_CR_NCHAR; 4901 else if (cap->nchar == NL) 4902 cap->nchar = REPLACE_NL_NCHAR; 4903 } 4904 nv_operator(cap); 4905 return; 4906 } 4907 4908 // Break tabs, etc. 4909 if (virtual_active()) 4910 { 4911 if (u_save_cursor() == FAIL) 4912 return; 4913 if (gchar_cursor() == NUL) 4914 { 4915 // Add extra space and put the cursor on the first one. 4916 coladvance_force((colnr_T)(getviscol() + cap->count1)); 4917 curwin->w_cursor.col -= cap->count1; 4918 } 4919 else if (gchar_cursor() == TAB) 4920 coladvance_force(getviscol()); 4921 } 4922 4923 // Abort if not enough characters to replace. 4924 ptr = ml_get_cursor(); 4925 if (STRLEN(ptr) < (unsigned)cap->count1 4926 || (has_mbyte && mb_charlen(ptr) < cap->count1)) 4927 { 4928 clearopbeep(cap->oap); 4929 return; 4930 } 4931 4932 /* 4933 * Replacing with a TAB is done by edit() when it is complicated because 4934 * 'expandtab' or 'smarttab' is set. CTRL-V TAB inserts a literal TAB. 4935 * Other characters are done below to avoid problems with things like 4936 * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC). 4937 */ 4938 if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || p_sta)) 4939 { 4940 stuffnumReadbuff(cap->count1); 4941 stuffcharReadbuff('R'); 4942 stuffcharReadbuff('\t'); 4943 stuffcharReadbuff(ESC); 4944 return; 4945 } 4946 4947 // save line for undo 4948 if (u_save_cursor() == FAIL) 4949 return; 4950 4951 if (had_ctrl_v != Ctrl_V && (cap->nchar == '\r' || cap->nchar == '\n')) 4952 { 4953 /* 4954 * Replace character(s) by a single newline. 4955 * Strange vi behaviour: Only one newline is inserted. 4956 * Delete the characters here. 4957 * Insert the newline with an insert command, takes care of 4958 * autoindent. The insert command depends on being on the last 4959 * character of a line or not. 4960 */ 4961 (void)del_chars(cap->count1, FALSE); // delete the characters 4962 stuffcharReadbuff('\r'); 4963 stuffcharReadbuff(ESC); 4964 4965 // Give 'r' to edit(), to get the redo command right. 4966 invoke_edit(cap, TRUE, 'r', FALSE); 4967 } 4968 else 4969 { 4970 prep_redo(cap->oap->regname, cap->count1, 4971 NUL, 'r', NUL, had_ctrl_v, cap->nchar); 4972 4973 curbuf->b_op_start = curwin->w_cursor; 4974 if (has_mbyte) 4975 { 4976 int old_State = State; 4977 4978 if (cap->ncharC1 != 0) 4979 AppendCharToRedobuff(cap->ncharC1); 4980 if (cap->ncharC2 != 0) 4981 AppendCharToRedobuff(cap->ncharC2); 4982 4983 // This is slow, but it handles replacing a single-byte with a 4984 // multi-byte and the other way around. Also handles adding 4985 // composing characters for utf-8. 4986 for (n = cap->count1; n > 0; --n) 4987 { 4988 State = REPLACE; 4989 if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y) 4990 { 4991 int c = ins_copychar(curwin->w_cursor.lnum 4992 + (cap->nchar == Ctrl_Y ? -1 : 1)); 4993 if (c != NUL) 4994 ins_char(c); 4995 else 4996 // will be decremented further down 4997 ++curwin->w_cursor.col; 4998 } 4999 else 5000 ins_char(cap->nchar); 5001 State = old_State; 5002 if (cap->ncharC1 != 0) 5003 ins_char(cap->ncharC1); 5004 if (cap->ncharC2 != 0) 5005 ins_char(cap->ncharC2); 5006 } 5007 } 5008 else 5009 { 5010 /* 5011 * Replace the characters within one line. 5012 */ 5013 for (n = cap->count1; n > 0; --n) 5014 { 5015 /* 5016 * Get ptr again, because u_save and/or showmatch() will have 5017 * released the line. At the same time we let know that the 5018 * line will be changed. 5019 */ 5020 ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE); 5021 if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y) 5022 { 5023 int c = ins_copychar(curwin->w_cursor.lnum 5024 + (cap->nchar == Ctrl_Y ? -1 : 1)); 5025 if (c != NUL) 5026 ptr[curwin->w_cursor.col] = c; 5027 } 5028 else 5029 ptr[curwin->w_cursor.col] = cap->nchar; 5030 if (p_sm && msg_silent == 0) 5031 showmatch(cap->nchar); 5032 ++curwin->w_cursor.col; 5033 } 5034 #ifdef FEAT_NETBEANS_INTG 5035 if (netbeans_active()) 5036 { 5037 colnr_T start = (colnr_T)(curwin->w_cursor.col - cap->count1); 5038 5039 netbeans_removed(curbuf, curwin->w_cursor.lnum, start, 5040 (long)cap->count1); 5041 netbeans_inserted(curbuf, curwin->w_cursor.lnum, start, 5042 &ptr[start], (int)cap->count1); 5043 } 5044 #endif 5045 5046 // mark the buffer as changed and prepare for displaying 5047 changed_bytes(curwin->w_cursor.lnum, 5048 (colnr_T)(curwin->w_cursor.col - cap->count1)); 5049 } 5050 --curwin->w_cursor.col; // cursor on the last replaced char 5051 // if the character on the left of the current cursor is a multi-byte 5052 // character, move two characters left 5053 if (has_mbyte) 5054 mb_adjust_cursor(); 5055 curbuf->b_op_end = curwin->w_cursor; 5056 curwin->w_set_curswant = TRUE; 5057 set_last_insert(cap->nchar); 5058 } 5059 } 5060 5061 /* 5062 * 'o': Exchange start and end of Visual area. 5063 * 'O': same, but in block mode exchange left and right corners. 5064 */ 5065 static void 5066 v_swap_corners(int cmdchar) 5067 { 5068 pos_T old_cursor; 5069 colnr_T left, right; 5070 5071 if (cmdchar == 'O' && VIsual_mode == Ctrl_V) 5072 { 5073 old_cursor = curwin->w_cursor; 5074 getvcols(curwin, &old_cursor, &VIsual, &left, &right); 5075 curwin->w_cursor.lnum = VIsual.lnum; 5076 coladvance(left); 5077 VIsual = curwin->w_cursor; 5078 5079 curwin->w_cursor.lnum = old_cursor.lnum; 5080 curwin->w_curswant = right; 5081 // 'selection "exclusive" and cursor at right-bottom corner: move it 5082 // right one column 5083 if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e') 5084 ++curwin->w_curswant; 5085 coladvance(curwin->w_curswant); 5086 if (curwin->w_cursor.col == old_cursor.col 5087 && (!virtual_active() 5088 || curwin->w_cursor.coladd == old_cursor.coladd)) 5089 { 5090 curwin->w_cursor.lnum = VIsual.lnum; 5091 if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e') 5092 ++right; 5093 coladvance(right); 5094 VIsual = curwin->w_cursor; 5095 5096 curwin->w_cursor.lnum = old_cursor.lnum; 5097 coladvance(left); 5098 curwin->w_curswant = left; 5099 } 5100 } 5101 else 5102 { 5103 old_cursor = curwin->w_cursor; 5104 curwin->w_cursor = VIsual; 5105 VIsual = old_cursor; 5106 curwin->w_set_curswant = TRUE; 5107 } 5108 } 5109 5110 /* 5111 * "R" (cap->arg is FALSE) and "gR" (cap->arg is TRUE). 5112 */ 5113 static void 5114 nv_Replace(cmdarg_T *cap) 5115 { 5116 if (VIsual_active) // "R" is replace lines 5117 { 5118 cap->cmdchar = 'c'; 5119 cap->nchar = NUL; 5120 VIsual_mode_orig = VIsual_mode; // remember original area for gv 5121 VIsual_mode = 'V'; 5122 nv_operator(cap); 5123 } 5124 else if (!checkclearopq(cap->oap)) 5125 { 5126 if (!curbuf->b_p_ma) 5127 emsg(_(e_modifiable)); 5128 else 5129 { 5130 if (virtual_active()) 5131 coladvance(getviscol()); 5132 invoke_edit(cap, FALSE, cap->arg ? 'V' : 'R', FALSE); 5133 } 5134 } 5135 } 5136 5137 /* 5138 * "gr". 5139 */ 5140 static void 5141 nv_vreplace(cmdarg_T *cap) 5142 { 5143 if (VIsual_active) 5144 { 5145 cap->cmdchar = 'r'; 5146 cap->nchar = cap->extra_char; 5147 nv_replace(cap); // Do same as "r" in Visual mode for now 5148 } 5149 else if (!checkclearopq(cap->oap)) 5150 { 5151 if (!curbuf->b_p_ma) 5152 emsg(_(e_modifiable)); 5153 else 5154 { 5155 if (cap->extra_char == Ctrl_V) // get another character 5156 cap->extra_char = get_literal(); 5157 stuffcharReadbuff(cap->extra_char); 5158 stuffcharReadbuff(ESC); 5159 if (virtual_active()) 5160 coladvance(getviscol()); 5161 invoke_edit(cap, TRUE, 'v', FALSE); 5162 } 5163 } 5164 } 5165 5166 /* 5167 * Swap case for "~" command, when it does not work like an operator. 5168 */ 5169 static void 5170 n_swapchar(cmdarg_T *cap) 5171 { 5172 long n; 5173 pos_T startpos; 5174 int did_change = 0; 5175 #ifdef FEAT_NETBEANS_INTG 5176 pos_T pos; 5177 char_u *ptr; 5178 int count; 5179 #endif 5180 5181 if (checkclearopq(cap->oap)) 5182 return; 5183 5184 if (LINEEMPTY(curwin->w_cursor.lnum) && vim_strchr(p_ww, '~') == NULL) 5185 { 5186 clearopbeep(cap->oap); 5187 return; 5188 } 5189 5190 prep_redo_cmd(cap); 5191 5192 if (u_save_cursor() == FAIL) 5193 return; 5194 5195 startpos = curwin->w_cursor; 5196 #ifdef FEAT_NETBEANS_INTG 5197 pos = startpos; 5198 #endif 5199 for (n = cap->count1; n > 0; --n) 5200 { 5201 did_change |= swapchar(cap->oap->op_type, &curwin->w_cursor); 5202 inc_cursor(); 5203 if (gchar_cursor() == NUL) 5204 { 5205 if (vim_strchr(p_ww, '~') != NULL 5206 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 5207 { 5208 #ifdef FEAT_NETBEANS_INTG 5209 if (netbeans_active()) 5210 { 5211 if (did_change) 5212 { 5213 ptr = ml_get(pos.lnum); 5214 count = (int)STRLEN(ptr) - pos.col; 5215 netbeans_removed(curbuf, pos.lnum, pos.col, 5216 (long)count); 5217 netbeans_inserted(curbuf, pos.lnum, pos.col, 5218 &ptr[pos.col], count); 5219 } 5220 pos.col = 0; 5221 pos.lnum++; 5222 } 5223 #endif 5224 ++curwin->w_cursor.lnum; 5225 curwin->w_cursor.col = 0; 5226 if (n > 1) 5227 { 5228 if (u_savesub(curwin->w_cursor.lnum) == FAIL) 5229 break; 5230 u_clearline(); 5231 } 5232 } 5233 else 5234 break; 5235 } 5236 } 5237 #ifdef FEAT_NETBEANS_INTG 5238 if (did_change && netbeans_active()) 5239 { 5240 ptr = ml_get(pos.lnum); 5241 count = curwin->w_cursor.col - pos.col; 5242 netbeans_removed(curbuf, pos.lnum, pos.col, (long)count); 5243 netbeans_inserted(curbuf, pos.lnum, pos.col, &ptr[pos.col], count); 5244 } 5245 #endif 5246 5247 5248 check_cursor(); 5249 curwin->w_set_curswant = TRUE; 5250 if (did_change) 5251 { 5252 changed_lines(startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1, 5253 0L); 5254 curbuf->b_op_start = startpos; 5255 curbuf->b_op_end = curwin->w_cursor; 5256 if (curbuf->b_op_end.col > 0) 5257 --curbuf->b_op_end.col; 5258 } 5259 } 5260 5261 /* 5262 * Move cursor to mark. 5263 */ 5264 static void 5265 nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos) 5266 { 5267 if (check_mark(pos) == FAIL) 5268 clearop(cap->oap); 5269 else 5270 { 5271 if (cap->cmdchar == '\'' 5272 || cap->cmdchar == '`' 5273 || cap->cmdchar == '[' 5274 || cap->cmdchar == ']') 5275 setpcmark(); 5276 curwin->w_cursor = *pos; 5277 if (flag) 5278 beginline(BL_WHITE | BL_FIX); 5279 else 5280 check_cursor(); 5281 } 5282 cap->oap->motion_type = flag ? MLINE : MCHAR; 5283 if (cap->cmdchar == '`') 5284 cap->oap->use_reg_one = TRUE; 5285 cap->oap->inclusive = FALSE; // ignored if not MCHAR 5286 curwin->w_set_curswant = TRUE; 5287 } 5288 5289 /* 5290 * Handle commands that are operators in Visual mode. 5291 */ 5292 static void 5293 v_visop(cmdarg_T *cap) 5294 { 5295 static char_u trans[] = "YyDdCcxdXdAAIIrr"; 5296 5297 // Uppercase means linewise, except in block mode, then "D" deletes till 5298 // the end of the line, and "C" replaces till EOL 5299 if (isupper(cap->cmdchar)) 5300 { 5301 if (VIsual_mode != Ctrl_V) 5302 { 5303 VIsual_mode_orig = VIsual_mode; 5304 VIsual_mode = 'V'; 5305 } 5306 else if (cap->cmdchar == 'C' || cap->cmdchar == 'D') 5307 curwin->w_curswant = MAXCOL; 5308 } 5309 cap->cmdchar = *(vim_strchr(trans, cap->cmdchar) + 1); 5310 nv_operator(cap); 5311 } 5312 5313 /* 5314 * "s" and "S" commands. 5315 */ 5316 static void 5317 nv_subst(cmdarg_T *cap) 5318 { 5319 #ifdef FEAT_TERMINAL 5320 // When showing output of term_dumpdiff() swap the top and botom. 5321 if (term_swap_diff() == OK) 5322 return; 5323 #endif 5324 #ifdef FEAT_JOB_CHANNEL 5325 if (bt_prompt(curbuf) && !prompt_curpos_editable()) 5326 { 5327 clearopbeep(cap->oap); 5328 return; 5329 } 5330 #endif 5331 if (VIsual_active) // "vs" and "vS" are the same as "vc" 5332 { 5333 if (cap->cmdchar == 'S') 5334 { 5335 VIsual_mode_orig = VIsual_mode; 5336 VIsual_mode = 'V'; 5337 } 5338 cap->cmdchar = 'c'; 5339 nv_operator(cap); 5340 } 5341 else 5342 nv_optrans(cap); 5343 } 5344 5345 /* 5346 * Abbreviated commands. 5347 */ 5348 static void 5349 nv_abbrev(cmdarg_T *cap) 5350 { 5351 if (cap->cmdchar == K_DEL || cap->cmdchar == K_KDEL) 5352 cap->cmdchar = 'x'; // DEL key behaves like 'x' 5353 5354 // in Visual mode these commands are operators 5355 if (VIsual_active) 5356 v_visop(cap); 5357 else 5358 nv_optrans(cap); 5359 } 5360 5361 /* 5362 * Translate a command into another command. 5363 */ 5364 static void 5365 nv_optrans(cmdarg_T *cap) 5366 { 5367 static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh", 5368 (char_u *)"d$", (char_u *)"c$", 5369 (char_u *)"cl", (char_u *)"cc", 5370 (char_u *)"yy", (char_u *)":s\r"}; 5371 static char_u *str = (char_u *)"xXDCsSY&"; 5372 5373 if (!checkclearopq(cap->oap)) 5374 { 5375 // In Vi "2D" doesn't delete the next line. Can't translate it 5376 // either, because "2." should also not use the count. 5377 if (cap->cmdchar == 'D' && vim_strchr(p_cpo, CPO_HASH) != NULL) 5378 { 5379 cap->oap->start = curwin->w_cursor; 5380 cap->oap->op_type = OP_DELETE; 5381 #ifdef FEAT_EVAL 5382 set_op_var(OP_DELETE); 5383 #endif 5384 cap->count1 = 1; 5385 nv_dollar(cap); 5386 finish_op = TRUE; 5387 ResetRedobuff(); 5388 AppendCharToRedobuff('D'); 5389 } 5390 else 5391 { 5392 if (cap->count0) 5393 stuffnumReadbuff(cap->count0); 5394 stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]); 5395 } 5396 } 5397 cap->opcount = 0; 5398 } 5399 5400 /* 5401 * "'" and "`" commands. Also for "g'" and "g`". 5402 * cap->arg is TRUE for "'" and "g'". 5403 */ 5404 static void 5405 nv_gomark(cmdarg_T *cap) 5406 { 5407 pos_T *pos; 5408 int c; 5409 #ifdef FEAT_FOLDING 5410 pos_T old_cursor = curwin->w_cursor; 5411 int old_KeyTyped = KeyTyped; // getting file may reset it 5412 #endif 5413 5414 if (cap->cmdchar == 'g') 5415 c = cap->extra_char; 5416 else 5417 c = cap->nchar; 5418 pos = getmark(c, (cap->oap->op_type == OP_NOP)); 5419 if (pos == (pos_T *)-1) // jumped to other file 5420 { 5421 if (cap->arg) 5422 { 5423 check_cursor_lnum(); 5424 beginline(BL_WHITE | BL_FIX); 5425 } 5426 else 5427 check_cursor(); 5428 } 5429 else 5430 nv_cursormark(cap, cap->arg, pos); 5431 5432 // May need to clear the coladd that a mark includes. 5433 if (!virtual_active()) 5434 curwin->w_cursor.coladd = 0; 5435 check_cursor_col(); 5436 #ifdef FEAT_FOLDING 5437 if (cap->oap->op_type == OP_NOP 5438 && pos != NULL 5439 && (pos == (pos_T *)-1 || !EQUAL_POS(old_cursor, *pos)) 5440 && (fdo_flags & FDO_MARK) 5441 && old_KeyTyped) 5442 foldOpenCursor(); 5443 #endif 5444 } 5445 5446 /* 5447 * Handle CTRL-O, CTRL-I, "g;", "g," and "CTRL-Tab" commands. 5448 */ 5449 static void 5450 nv_pcmark(cmdarg_T *cap) 5451 { 5452 #ifdef FEAT_JUMPLIST 5453 pos_T *pos; 5454 # ifdef FEAT_FOLDING 5455 linenr_T lnum = curwin->w_cursor.lnum; 5456 int old_KeyTyped = KeyTyped; // getting file may reset it 5457 # endif 5458 5459 if (!checkclearopq(cap->oap)) 5460 { 5461 if (cap->cmdchar == TAB && mod_mask == MOD_MASK_CTRL) 5462 { 5463 if (goto_tabpage_lastused() == FAIL) 5464 clearopbeep(cap->oap); 5465 return; 5466 } 5467 if (cap->cmdchar == 'g') 5468 pos = movechangelist((int)cap->count1); 5469 else 5470 pos = movemark((int)cap->count1); 5471 if (pos == (pos_T *)-1) // jump to other file 5472 { 5473 curwin->w_set_curswant = TRUE; 5474 check_cursor(); 5475 } 5476 else if (pos != NULL) // can jump 5477 nv_cursormark(cap, FALSE, pos); 5478 else if (cap->cmdchar == 'g') 5479 { 5480 if (curbuf->b_changelistlen == 0) 5481 emsg(_("E664: changelist is empty")); 5482 else if (cap->count1 < 0) 5483 emsg(_("E662: At start of changelist")); 5484 else 5485 emsg(_("E663: At end of changelist")); 5486 } 5487 else 5488 clearopbeep(cap->oap); 5489 # ifdef FEAT_FOLDING 5490 if (cap->oap->op_type == OP_NOP 5491 && (pos == (pos_T *)-1 || lnum != curwin->w_cursor.lnum) 5492 && (fdo_flags & FDO_MARK) 5493 && old_KeyTyped) 5494 foldOpenCursor(); 5495 # endif 5496 } 5497 #else 5498 clearopbeep(cap->oap); 5499 #endif 5500 } 5501 5502 /* 5503 * Handle '"' command. 5504 */ 5505 static void 5506 nv_regname(cmdarg_T *cap) 5507 { 5508 if (checkclearop(cap->oap)) 5509 return; 5510 #ifdef FEAT_EVAL 5511 if (cap->nchar == '=') 5512 cap->nchar = get_expr_register(); 5513 #endif 5514 if (cap->nchar != NUL && valid_yank_reg(cap->nchar, FALSE)) 5515 { 5516 cap->oap->regname = cap->nchar; 5517 cap->opcount = cap->count0; // remember count before '"' 5518 #ifdef FEAT_EVAL 5519 set_reg_var(cap->oap->regname); 5520 #endif 5521 } 5522 else 5523 clearopbeep(cap->oap); 5524 } 5525 5526 /* 5527 * Handle "v", "V" and "CTRL-V" commands. 5528 * Also for "gh", "gH" and "g^H" commands: Always start Select mode, cap->arg 5529 * is TRUE. 5530 * Handle CTRL-Q just like CTRL-V. 5531 */ 5532 static void 5533 nv_visual(cmdarg_T *cap) 5534 { 5535 if (cap->cmdchar == Ctrl_Q) 5536 cap->cmdchar = Ctrl_V; 5537 5538 // 'v', 'V' and CTRL-V can be used while an operator is pending to make it 5539 // characterwise, linewise, or blockwise. 5540 if (cap->oap->op_type != OP_NOP) 5541 { 5542 motion_force = cap->oap->motion_force = cap->cmdchar; 5543 finish_op = FALSE; // operator doesn't finish now but later 5544 return; 5545 } 5546 5547 VIsual_select = cap->arg; 5548 if (VIsual_active) // change Visual mode 5549 { 5550 if (VIsual_mode == cap->cmdchar) // stop visual mode 5551 end_visual_mode(); 5552 else // toggle char/block mode 5553 { // or char/line mode 5554 VIsual_mode = cap->cmdchar; 5555 showmode(); 5556 } 5557 redraw_curbuf_later(INVERTED); // update the inversion 5558 } 5559 else // start Visual mode 5560 { 5561 check_visual_highlight(); 5562 if (cap->count0 > 0 && resel_VIsual_mode != NUL) 5563 { 5564 // use previously selected part 5565 VIsual = curwin->w_cursor; 5566 5567 VIsual_active = TRUE; 5568 VIsual_reselect = TRUE; 5569 if (!cap->arg) 5570 // start Select mode when 'selectmode' contains "cmd" 5571 may_start_select('c'); 5572 setmouse(); 5573 if (p_smd && msg_silent == 0) 5574 redraw_cmdline = TRUE; // show visual mode later 5575 /* 5576 * For V and ^V, we multiply the number of lines even if there 5577 * was only one -- webb 5578 */ 5579 if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1) 5580 { 5581 curwin->w_cursor.lnum += 5582 resel_VIsual_line_count * cap->count0 - 1; 5583 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 5584 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 5585 } 5586 VIsual_mode = resel_VIsual_mode; 5587 if (VIsual_mode == 'v') 5588 { 5589 if (resel_VIsual_line_count <= 1) 5590 { 5591 validate_virtcol(); 5592 curwin->w_curswant = curwin->w_virtcol 5593 + resel_VIsual_vcol * cap->count0 - 1; 5594 } 5595 else 5596 curwin->w_curswant = resel_VIsual_vcol; 5597 coladvance(curwin->w_curswant); 5598 } 5599 if (resel_VIsual_vcol == MAXCOL) 5600 { 5601 curwin->w_curswant = MAXCOL; 5602 coladvance((colnr_T)MAXCOL); 5603 } 5604 else if (VIsual_mode == Ctrl_V) 5605 { 5606 validate_virtcol(); 5607 curwin->w_curswant = curwin->w_virtcol 5608 + resel_VIsual_vcol * cap->count0 - 1; 5609 coladvance(curwin->w_curswant); 5610 } 5611 else 5612 curwin->w_set_curswant = TRUE; 5613 redraw_curbuf_later(INVERTED); // show the inversion 5614 } 5615 else 5616 { 5617 if (!cap->arg) 5618 // start Select mode when 'selectmode' contains "cmd" 5619 may_start_select('c'); 5620 n_start_visual_mode(cap->cmdchar); 5621 if (VIsual_mode != 'V' && *p_sel == 'e') 5622 ++cap->count1; // include one more char 5623 if (cap->count0 > 0 && --cap->count1 > 0) 5624 { 5625 // With a count select that many characters or lines. 5626 if (VIsual_mode == 'v' || VIsual_mode == Ctrl_V) 5627 nv_right(cap); 5628 else if (VIsual_mode == 'V') 5629 nv_down(cap); 5630 } 5631 } 5632 } 5633 } 5634 5635 /* 5636 * Start selection for Shift-movement keys. 5637 */ 5638 void 5639 start_selection(void) 5640 { 5641 // if 'selectmode' contains "key", start Select mode 5642 may_start_select('k'); 5643 n_start_visual_mode('v'); 5644 } 5645 5646 /* 5647 * Start Select mode, if "c" is in 'selectmode' and not in a mapping or menu. 5648 */ 5649 void 5650 may_start_select(int c) 5651 { 5652 VIsual_select = (stuff_empty() && typebuf_typed() 5653 && (vim_strchr(p_slm, c) != NULL)); 5654 } 5655 5656 /* 5657 * Start Visual mode "c". 5658 * Should set VIsual_select before calling this. 5659 */ 5660 static void 5661 n_start_visual_mode(int c) 5662 { 5663 #ifdef FEAT_CONCEAL 5664 // Check for redraw before changing the state. 5665 conceal_check_cursor_line(); 5666 #endif 5667 5668 VIsual_mode = c; 5669 VIsual_active = TRUE; 5670 VIsual_reselect = TRUE; 5671 5672 // Corner case: the 0 position in a tab may change when going into 5673 // virtualedit. Recalculate curwin->w_cursor to avoid bad highlighting. 5674 if (c == Ctrl_V && (ve_flags & VE_BLOCK) && gchar_cursor() == TAB) 5675 { 5676 validate_virtcol(); 5677 coladvance(curwin->w_virtcol); 5678 } 5679 VIsual = curwin->w_cursor; 5680 5681 #ifdef FEAT_FOLDING 5682 foldAdjustVisual(); 5683 #endif 5684 5685 setmouse(); 5686 #ifdef FEAT_CONCEAL 5687 // Check for redraw after changing the state. 5688 conceal_check_cursor_line(); 5689 #endif 5690 5691 if (p_smd && msg_silent == 0) 5692 redraw_cmdline = TRUE; // show visual mode later 5693 #ifdef FEAT_CLIPBOARD 5694 // Make sure the clipboard gets updated. Needed because start and 5695 // end may still be the same, and the selection needs to be owned 5696 clip_star.vmode = NUL; 5697 #endif 5698 5699 // Only need to redraw this line, unless still need to redraw an old 5700 // Visual area (when 'lazyredraw' is set). 5701 if (curwin->w_redr_type < INVERTED) 5702 { 5703 curwin->w_old_cursor_lnum = curwin->w_cursor.lnum; 5704 curwin->w_old_visual_lnum = curwin->w_cursor.lnum; 5705 } 5706 } 5707 5708 5709 /* 5710 * CTRL-W: Window commands 5711 */ 5712 static void 5713 nv_window(cmdarg_T *cap) 5714 { 5715 if (cap->nchar == ':') 5716 { 5717 // "CTRL-W :" is the same as typing ":"; useful in a terminal window 5718 cap->cmdchar = ':'; 5719 cap->nchar = NUL; 5720 nv_colon(cap); 5721 } 5722 else if (!checkclearop(cap->oap)) 5723 do_window(cap->nchar, cap->count0, NUL); // everything is in window.c 5724 } 5725 5726 /* 5727 * CTRL-Z: Suspend 5728 */ 5729 static void 5730 nv_suspend(cmdarg_T *cap) 5731 { 5732 clearop(cap->oap); 5733 if (VIsual_active) 5734 end_visual_mode(); // stop Visual mode 5735 do_cmdline_cmd((char_u *)"st"); 5736 } 5737 5738 /* 5739 * Commands starting with "g". 5740 */ 5741 static void 5742 nv_g_cmd(cmdarg_T *cap) 5743 { 5744 oparg_T *oap = cap->oap; 5745 pos_T tpos; 5746 int i; 5747 int flag = FALSE; 5748 5749 switch (cap->nchar) 5750 { 5751 case Ctrl_A: 5752 case Ctrl_X: 5753 #ifdef MEM_PROFILE 5754 /* 5755 * "g^A": dump log of used memory. 5756 */ 5757 if (!VIsual_active && cap->nchar == Ctrl_A) 5758 vim_mem_profile_dump(); 5759 else 5760 #endif 5761 /* 5762 * "g^A/g^X": sequentially increment visually selected region 5763 */ 5764 if (VIsual_active) 5765 { 5766 cap->arg = TRUE; 5767 cap->cmdchar = cap->nchar; 5768 cap->nchar = NUL; 5769 nv_addsub(cap); 5770 } 5771 else 5772 clearopbeep(oap); 5773 break; 5774 5775 /* 5776 * "gR": Enter virtual replace mode. 5777 */ 5778 case 'R': 5779 cap->arg = TRUE; 5780 nv_Replace(cap); 5781 break; 5782 5783 case 'r': 5784 nv_vreplace(cap); 5785 break; 5786 5787 case '&': 5788 do_cmdline_cmd((char_u *)"%s//~/&"); 5789 break; 5790 5791 /* 5792 * "gv": Reselect the previous Visual area. If Visual already active, 5793 * exchange previous and current Visual area. 5794 */ 5795 case 'v': 5796 if (checkclearop(oap)) 5797 break; 5798 5799 if ( curbuf->b_visual.vi_start.lnum == 0 5800 || curbuf->b_visual.vi_start.lnum > curbuf->b_ml.ml_line_count 5801 || curbuf->b_visual.vi_end.lnum == 0) 5802 beep_flush(); 5803 else 5804 { 5805 // set w_cursor to the start of the Visual area, tpos to the end 5806 if (VIsual_active) 5807 { 5808 i = VIsual_mode; 5809 VIsual_mode = curbuf->b_visual.vi_mode; 5810 curbuf->b_visual.vi_mode = i; 5811 # ifdef FEAT_EVAL 5812 curbuf->b_visual_mode_eval = i; 5813 # endif 5814 i = curwin->w_curswant; 5815 curwin->w_curswant = curbuf->b_visual.vi_curswant; 5816 curbuf->b_visual.vi_curswant = i; 5817 5818 tpos = curbuf->b_visual.vi_end; 5819 curbuf->b_visual.vi_end = curwin->w_cursor; 5820 curwin->w_cursor = curbuf->b_visual.vi_start; 5821 curbuf->b_visual.vi_start = VIsual; 5822 } 5823 else 5824 { 5825 VIsual_mode = curbuf->b_visual.vi_mode; 5826 curwin->w_curswant = curbuf->b_visual.vi_curswant; 5827 tpos = curbuf->b_visual.vi_end; 5828 curwin->w_cursor = curbuf->b_visual.vi_start; 5829 } 5830 5831 VIsual_active = TRUE; 5832 VIsual_reselect = TRUE; 5833 5834 // Set Visual to the start and w_cursor to the end of the Visual 5835 // area. Make sure they are on an existing character. 5836 check_cursor(); 5837 VIsual = curwin->w_cursor; 5838 curwin->w_cursor = tpos; 5839 check_cursor(); 5840 update_topline(); 5841 /* 5842 * When called from normal "g" command: start Select mode when 5843 * 'selectmode' contains "cmd". When called for K_SELECT, always 5844 * start Select mode. 5845 */ 5846 if (cap->arg) 5847 VIsual_select = TRUE; 5848 else 5849 may_start_select('c'); 5850 setmouse(); 5851 #ifdef FEAT_CLIPBOARD 5852 // Make sure the clipboard gets updated. Needed because start and 5853 // end are still the same, and the selection needs to be owned 5854 clip_star.vmode = NUL; 5855 #endif 5856 redraw_curbuf_later(INVERTED); 5857 showmode(); 5858 } 5859 break; 5860 /* 5861 * "gV": Don't reselect the previous Visual area after a Select mode 5862 * mapping of menu. 5863 */ 5864 case 'V': 5865 VIsual_reselect = FALSE; 5866 break; 5867 5868 /* 5869 * "gh": start Select mode. 5870 * "gH": start Select line mode. 5871 * "g^H": start Select block mode. 5872 */ 5873 case K_BS: 5874 cap->nchar = Ctrl_H; 5875 // FALLTHROUGH 5876 case 'h': 5877 case 'H': 5878 case Ctrl_H: 5879 # ifdef EBCDIC 5880 // EBCDIC: 'v'-'h' != '^v'-'^h' 5881 if (cap->nchar == Ctrl_H) 5882 cap->cmdchar = Ctrl_V; 5883 else 5884 # endif 5885 cap->cmdchar = cap->nchar + ('v' - 'h'); 5886 cap->arg = TRUE; 5887 nv_visual(cap); 5888 break; 5889 5890 // "gn", "gN" visually select next/previous search match 5891 // "gn" selects next match 5892 // "gN" selects previous match 5893 case 'N': 5894 case 'n': 5895 if (!current_search(cap->count1, cap->nchar == 'n')) 5896 clearopbeep(oap); 5897 break; 5898 5899 /* 5900 * "gj" and "gk" two new funny movement keys -- up and down 5901 * movement based on *screen* line rather than *file* line. 5902 */ 5903 case 'j': 5904 case K_DOWN: 5905 // with 'nowrap' it works just like the normal "j" command; also when 5906 // in a closed fold 5907 if (!curwin->w_p_wrap 5908 #ifdef FEAT_FOLDING 5909 || hasFolding(curwin->w_cursor.lnum, NULL, NULL) 5910 #endif 5911 ) 5912 { 5913 oap->motion_type = MLINE; 5914 i = cursor_down(cap->count1, oap->op_type == OP_NOP); 5915 } 5916 else 5917 i = nv_screengo(oap, FORWARD, cap->count1); 5918 if (i == FAIL) 5919 clearopbeep(oap); 5920 break; 5921 5922 case 'k': 5923 case K_UP: 5924 // with 'nowrap' it works just like the normal "k" command; also when 5925 // in a closed fold 5926 if (!curwin->w_p_wrap 5927 #ifdef FEAT_FOLDING 5928 || hasFolding(curwin->w_cursor.lnum, NULL, NULL) 5929 #endif 5930 ) 5931 { 5932 oap->motion_type = MLINE; 5933 i = cursor_up(cap->count1, oap->op_type == OP_NOP); 5934 } 5935 else 5936 i = nv_screengo(oap, BACKWARD, cap->count1); 5937 if (i == FAIL) 5938 clearopbeep(oap); 5939 break; 5940 5941 /* 5942 * "gJ": join two lines without inserting a space. 5943 */ 5944 case 'J': 5945 nv_join(cap); 5946 break; 5947 5948 /* 5949 * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines. 5950 * "gm": middle of "g0" and "g$". 5951 */ 5952 case '^': 5953 flag = TRUE; 5954 // FALLTHROUGH 5955 5956 case '0': 5957 case 'm': 5958 case K_HOME: 5959 case K_KHOME: 5960 oap->motion_type = MCHAR; 5961 oap->inclusive = FALSE; 5962 if (curwin->w_p_wrap && curwin->w_width != 0) 5963 { 5964 int width1 = curwin->w_width - curwin_col_off(); 5965 int width2 = width1 + curwin_col_off2(); 5966 5967 validate_virtcol(); 5968 i = 0; 5969 if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0) 5970 i = (curwin->w_virtcol - width1) / width2 * width2 + width1; 5971 } 5972 else 5973 i = curwin->w_leftcol; 5974 // Go to the middle of the screen line. When 'number' or 5975 // 'relativenumber' is on and lines are wrapping the middle can be more 5976 // to the left. 5977 if (cap->nchar == 'm') 5978 i += (curwin->w_width - curwin_col_off() 5979 + ((curwin->w_p_wrap && i > 0) 5980 ? curwin_col_off2() : 0)) / 2; 5981 coladvance((colnr_T)i); 5982 if (flag) 5983 { 5984 do 5985 i = gchar_cursor(); 5986 while (VIM_ISWHITE(i) && oneright() == OK); 5987 curwin->w_valid &= ~VALID_WCOL; 5988 } 5989 curwin->w_set_curswant = TRUE; 5990 break; 5991 5992 case 'M': 5993 { 5994 char_u *ptr = ml_get_curline(); 5995 5996 oap->motion_type = MCHAR; 5997 oap->inclusive = FALSE; 5998 if (has_mbyte) 5999 i = mb_string2cells(ptr, (int)STRLEN(ptr)); 6000 else 6001 i = (int)STRLEN(ptr); 6002 if (cap->count0 > 0 && cap->count0 <= 100) 6003 coladvance((colnr_T)(i * cap->count0 / 100)); 6004 else 6005 coladvance((colnr_T)(i / 2)); 6006 curwin->w_set_curswant = TRUE; 6007 } 6008 break; 6009 6010 case '_': 6011 // "g_": to the last non-blank character in the line or <count> lines 6012 // downward. 6013 cap->oap->motion_type = MCHAR; 6014 cap->oap->inclusive = TRUE; 6015 curwin->w_curswant = MAXCOL; 6016 if (cursor_down((long)(cap->count1 - 1), 6017 cap->oap->op_type == OP_NOP) == FAIL) 6018 clearopbeep(cap->oap); 6019 else 6020 { 6021 char_u *ptr = ml_get_curline(); 6022 6023 // In Visual mode we may end up after the line. 6024 if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL) 6025 --curwin->w_cursor.col; 6026 6027 // Decrease the cursor column until it's on a non-blank. 6028 while (curwin->w_cursor.col > 0 6029 && VIM_ISWHITE(ptr[curwin->w_cursor.col])) 6030 --curwin->w_cursor.col; 6031 curwin->w_set_curswant = TRUE; 6032 adjust_for_sel(cap); 6033 } 6034 break; 6035 6036 case '$': 6037 case K_END: 6038 case K_KEND: 6039 { 6040 int col_off = curwin_col_off(); 6041 6042 oap->motion_type = MCHAR; 6043 oap->inclusive = TRUE; 6044 if (curwin->w_p_wrap && curwin->w_width != 0) 6045 { 6046 curwin->w_curswant = MAXCOL; // so we stay at the end 6047 if (cap->count1 == 1) 6048 { 6049 int width1 = curwin->w_width - col_off; 6050 int width2 = width1 + curwin_col_off2(); 6051 6052 validate_virtcol(); 6053 i = width1 - 1; 6054 if (curwin->w_virtcol >= (colnr_T)width1) 6055 i += ((curwin->w_virtcol - width1) / width2 + 1) 6056 * width2; 6057 coladvance((colnr_T)i); 6058 6059 // Make sure we stick in this column. 6060 validate_virtcol(); 6061 curwin->w_curswant = curwin->w_virtcol; 6062 curwin->w_set_curswant = FALSE; 6063 if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) 6064 { 6065 /* 6066 * Check for landing on a character that got split at 6067 * the end of the line. We do not want to advance to 6068 * the next screen line. 6069 */ 6070 if (curwin->w_virtcol > (colnr_T)i) 6071 --curwin->w_cursor.col; 6072 } 6073 } 6074 else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == FAIL) 6075 clearopbeep(oap); 6076 } 6077 else 6078 { 6079 if (cap->count1 > 1) 6080 // if it fails, let the cursor still move to the last char 6081 (void)cursor_down(cap->count1 - 1, FALSE); 6082 6083 i = curwin->w_leftcol + curwin->w_width - col_off - 1; 6084 coladvance((colnr_T)i); 6085 6086 // Make sure we stick in this column. 6087 validate_virtcol(); 6088 curwin->w_curswant = curwin->w_virtcol; 6089 curwin->w_set_curswant = FALSE; 6090 } 6091 } 6092 break; 6093 6094 /* 6095 * "g*" and "g#", like "*" and "#" but without using "\<" and "\>" 6096 */ 6097 case '*': 6098 case '#': 6099 #if POUND != '#' 6100 case POUND: // pound sign (sometimes equal to '#') 6101 #endif 6102 case Ctrl_RSB: // :tag or :tselect for current identifier 6103 case ']': // :tselect for current identifier 6104 nv_ident(cap); 6105 break; 6106 6107 /* 6108 * ge and gE: go back to end of word 6109 */ 6110 case 'e': 6111 case 'E': 6112 oap->motion_type = MCHAR; 6113 curwin->w_set_curswant = TRUE; 6114 oap->inclusive = TRUE; 6115 if (bckend_word(cap->count1, cap->nchar == 'E', FALSE) == FAIL) 6116 clearopbeep(oap); 6117 break; 6118 6119 /* 6120 * "g CTRL-G": display info about cursor position 6121 */ 6122 case Ctrl_G: 6123 cursor_pos_info(NULL); 6124 break; 6125 6126 /* 6127 * "gi": start Insert at the last position. 6128 */ 6129 case 'i': 6130 if (curbuf->b_last_insert.lnum != 0) 6131 { 6132 curwin->w_cursor = curbuf->b_last_insert; 6133 check_cursor_lnum(); 6134 i = (int)STRLEN(ml_get_curline()); 6135 if (curwin->w_cursor.col > (colnr_T)i) 6136 { 6137 if (virtual_active()) 6138 curwin->w_cursor.coladd += curwin->w_cursor.col - i; 6139 curwin->w_cursor.col = i; 6140 } 6141 } 6142 cap->cmdchar = 'i'; 6143 nv_edit(cap); 6144 break; 6145 6146 /* 6147 * "gI": Start insert in column 1. 6148 */ 6149 case 'I': 6150 beginline(0); 6151 if (!checkclearopq(oap)) 6152 invoke_edit(cap, FALSE, 'g', FALSE); 6153 break; 6154 6155 #ifdef FEAT_SEARCHPATH 6156 /* 6157 * "gf": goto file, edit file under cursor 6158 * "]f" and "[f": can also be used. 6159 */ 6160 case 'f': 6161 case 'F': 6162 nv_gotofile(cap); 6163 break; 6164 #endif 6165 6166 // "g'm" and "g`m": jump to mark without setting pcmark 6167 case '\'': 6168 cap->arg = TRUE; 6169 // FALLTHROUGH 6170 case '`': 6171 nv_gomark(cap); 6172 break; 6173 6174 /* 6175 * "gs": Goto sleep. 6176 */ 6177 case 's': 6178 do_sleep(cap->count1 * 1000L); 6179 break; 6180 6181 /* 6182 * "ga": Display the ascii value of the character under the 6183 * cursor. It is displayed in decimal, hex, and octal. -- webb 6184 */ 6185 case 'a': 6186 do_ascii(NULL); 6187 break; 6188 6189 /* 6190 * "g8": Display the bytes used for the UTF-8 character under the 6191 * cursor. It is displayed in hex. 6192 * "8g8" finds illegal byte sequence. 6193 */ 6194 case '8': 6195 if (cap->count0 == 8) 6196 utf_find_illegal(); 6197 else 6198 show_utf8(); 6199 break; 6200 6201 // "g<": show scrollback text 6202 case '<': 6203 show_sb_text(); 6204 break; 6205 6206 /* 6207 * "gg": Goto the first line in file. With a count it goes to 6208 * that line number like for "G". -- webb 6209 */ 6210 case 'g': 6211 cap->arg = FALSE; 6212 nv_goto(cap); 6213 break; 6214 6215 /* 6216 * Two-character operators: 6217 * "gq" Format text 6218 * "gw" Format text and keep cursor position 6219 * "g~" Toggle the case of the text. 6220 * "gu" Change text to lower case. 6221 * "gU" Change text to upper case. 6222 * "g?" rot13 encoding 6223 * "g@" call 'operatorfunc' 6224 */ 6225 case 'q': 6226 case 'w': 6227 oap->cursor_start = curwin->w_cursor; 6228 // FALLTHROUGH 6229 case '~': 6230 case 'u': 6231 case 'U': 6232 case '?': 6233 case '@': 6234 nv_operator(cap); 6235 break; 6236 6237 /* 6238 * "gd": Find first occurrence of pattern under the cursor in the 6239 * current function 6240 * "gD": idem, but in the current file. 6241 */ 6242 case 'd': 6243 case 'D': 6244 nv_gd(oap, cap->nchar, (int)cap->count0); 6245 break; 6246 6247 /* 6248 * g<*Mouse> : <C-*mouse> 6249 */ 6250 case K_MIDDLEMOUSE: 6251 case K_MIDDLEDRAG: 6252 case K_MIDDLERELEASE: 6253 case K_LEFTMOUSE: 6254 case K_LEFTDRAG: 6255 case K_LEFTRELEASE: 6256 case K_MOUSEMOVE: 6257 case K_RIGHTMOUSE: 6258 case K_RIGHTDRAG: 6259 case K_RIGHTRELEASE: 6260 case K_X1MOUSE: 6261 case K_X1DRAG: 6262 case K_X1RELEASE: 6263 case K_X2MOUSE: 6264 case K_X2DRAG: 6265 case K_X2RELEASE: 6266 mod_mask = MOD_MASK_CTRL; 6267 (void)do_mouse(oap, cap->nchar, BACKWARD, cap->count1, 0); 6268 break; 6269 6270 case K_IGNORE: 6271 break; 6272 6273 /* 6274 * "gP" and "gp": same as "P" and "p" but leave cursor just after new text 6275 */ 6276 case 'p': 6277 case 'P': 6278 nv_put(cap); 6279 break; 6280 6281 #ifdef FEAT_BYTEOFF 6282 // "go": goto byte count from start of buffer 6283 case 'o': 6284 goto_byte(cap->count0); 6285 break; 6286 #endif 6287 6288 // "gQ": improved Ex mode 6289 case 'Q': 6290 if (text_locked()) 6291 { 6292 clearopbeep(cap->oap); 6293 text_locked_msg(); 6294 break; 6295 } 6296 6297 if (!checkclearopq(oap)) 6298 do_exmode(TRUE); 6299 break; 6300 6301 #ifdef FEAT_JUMPLIST 6302 case ',': 6303 nv_pcmark(cap); 6304 break; 6305 6306 case ';': 6307 cap->count1 = -cap->count1; 6308 nv_pcmark(cap); 6309 break; 6310 #endif 6311 6312 case 't': 6313 if (!checkclearop(oap)) 6314 goto_tabpage((int)cap->count0); 6315 break; 6316 case 'T': 6317 if (!checkclearop(oap)) 6318 goto_tabpage(-(int)cap->count1); 6319 break; 6320 6321 case TAB: 6322 if (!checkclearop(oap) && goto_tabpage_lastused() == FAIL) 6323 clearopbeep(oap); 6324 break; 6325 6326 case '+': 6327 case '-': // "g+" and "g-": undo or redo along the timeline 6328 if (!checkclearopq(oap)) 6329 undo_time(cap->nchar == '-' ? -cap->count1 : cap->count1, 6330 FALSE, FALSE, FALSE); 6331 break; 6332 6333 default: 6334 clearopbeep(oap); 6335 break; 6336 } 6337 } 6338 6339 /* 6340 * Handle "o" and "O" commands. 6341 */ 6342 static void 6343 n_opencmd(cmdarg_T *cap) 6344 { 6345 #ifdef FEAT_CONCEAL 6346 linenr_T oldline = curwin->w_cursor.lnum; 6347 #endif 6348 6349 if (!checkclearopq(cap->oap)) 6350 { 6351 #ifdef FEAT_FOLDING 6352 if (cap->cmdchar == 'O') 6353 // Open above the first line of a folded sequence of lines 6354 (void)hasFolding(curwin->w_cursor.lnum, 6355 &curwin->w_cursor.lnum, NULL); 6356 else 6357 // Open below the last line of a folded sequence of lines 6358 (void)hasFolding(curwin->w_cursor.lnum, 6359 NULL, &curwin->w_cursor.lnum); 6360 #endif 6361 if (u_save((linenr_T)(curwin->w_cursor.lnum - 6362 (cap->cmdchar == 'O' ? 1 : 0)), 6363 (linenr_T)(curwin->w_cursor.lnum + 6364 (cap->cmdchar == 'o' ? 1 : 0)) 6365 ) == OK 6366 && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD, 6367 has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0, 6368 0) == OK) 6369 { 6370 #ifdef FEAT_CONCEAL 6371 if (curwin->w_p_cole > 0 && oldline != curwin->w_cursor.lnum) 6372 redrawWinline(curwin, oldline); 6373 #endif 6374 #ifdef FEAT_SYN_HL 6375 if (curwin->w_p_cul) 6376 // force redraw of cursorline 6377 curwin->w_valid &= ~VALID_CROW; 6378 #endif 6379 // When '#' is in 'cpoptions' ignore the count. 6380 if (vim_strchr(p_cpo, CPO_HASH) != NULL) 6381 cap->count1 = 1; 6382 invoke_edit(cap, FALSE, cap->cmdchar, TRUE); 6383 } 6384 } 6385 } 6386 6387 /* 6388 * "." command: redo last change. 6389 */ 6390 static void 6391 nv_dot(cmdarg_T *cap) 6392 { 6393 if (!checkclearopq(cap->oap)) 6394 { 6395 /* 6396 * If "restart_edit" is TRUE, the last but one command is repeated 6397 * instead of the last command (inserting text). This is used for 6398 * CTRL-O <.> in insert mode. 6399 */ 6400 if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == FAIL) 6401 clearopbeep(cap->oap); 6402 } 6403 } 6404 6405 /* 6406 * CTRL-R: undo undo 6407 */ 6408 static void 6409 nv_redo(cmdarg_T *cap) 6410 { 6411 if (!checkclearopq(cap->oap)) 6412 { 6413 u_redo((int)cap->count1); 6414 curwin->w_set_curswant = TRUE; 6415 } 6416 } 6417 6418 /* 6419 * Handle "U" command. 6420 */ 6421 static void 6422 nv_Undo(cmdarg_T *cap) 6423 { 6424 // In Visual mode and typing "gUU" triggers an operator 6425 if (cap->oap->op_type == OP_UPPER || VIsual_active) 6426 { 6427 // translate "gUU" to "gUgU" 6428 cap->cmdchar = 'g'; 6429 cap->nchar = 'U'; 6430 nv_operator(cap); 6431 } 6432 else if (!checkclearopq(cap->oap)) 6433 { 6434 u_undoline(); 6435 curwin->w_set_curswant = TRUE; 6436 } 6437 } 6438 6439 /* 6440 * '~' command: If tilde is not an operator and Visual is off: swap case of a 6441 * single character. 6442 */ 6443 static void 6444 nv_tilde(cmdarg_T *cap) 6445 { 6446 if (!p_to && !VIsual_active && cap->oap->op_type != OP_TILDE) 6447 { 6448 #ifdef FEAT_JOB_CHANNEL 6449 if (bt_prompt(curbuf) && !prompt_curpos_editable()) 6450 { 6451 clearopbeep(cap->oap); 6452 return; 6453 } 6454 #endif 6455 n_swapchar(cap); 6456 } 6457 else 6458 nv_operator(cap); 6459 } 6460 6461 /* 6462 * Handle an operator command. 6463 * The actual work is done by do_pending_operator(). 6464 */ 6465 static void 6466 nv_operator(cmdarg_T *cap) 6467 { 6468 int op_type; 6469 6470 op_type = get_op_type(cap->cmdchar, cap->nchar); 6471 #ifdef FEAT_JOB_CHANNEL 6472 if (bt_prompt(curbuf) && op_is_change(op_type) && !prompt_curpos_editable()) 6473 { 6474 clearopbeep(cap->oap); 6475 return; 6476 } 6477 #endif 6478 6479 if (op_type == cap->oap->op_type) // double operator works on lines 6480 nv_lineop(cap); 6481 else if (!checkclearop(cap->oap)) 6482 { 6483 cap->oap->start = curwin->w_cursor; 6484 cap->oap->op_type = op_type; 6485 #ifdef FEAT_EVAL 6486 set_op_var(op_type); 6487 #endif 6488 } 6489 } 6490 6491 #ifdef FEAT_EVAL 6492 /* 6493 * Set v:operator to the characters for "optype". 6494 */ 6495 static void 6496 set_op_var(int optype) 6497 { 6498 char_u opchars[3]; 6499 6500 if (optype == OP_NOP) 6501 set_vim_var_string(VV_OP, NULL, 0); 6502 else 6503 { 6504 opchars[0] = get_op_char(optype); 6505 opchars[1] = get_extra_op_char(optype); 6506 opchars[2] = NUL; 6507 set_vim_var_string(VV_OP, opchars, -1); 6508 } 6509 } 6510 #endif 6511 6512 /* 6513 * Handle linewise operator "dd", "yy", etc. 6514 * 6515 * "_" is is a strange motion command that helps make operators more logical. 6516 * It is actually implemented, but not documented in the real Vi. This motion 6517 * command actually refers to "the current line". Commands like "dd" and "yy" 6518 * are really an alternate form of "d_" and "y_". It does accept a count, so 6519 * "d3_" works to delete 3 lines. 6520 */ 6521 static void 6522 nv_lineop(cmdarg_T *cap) 6523 { 6524 cap->oap->motion_type = MLINE; 6525 if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == FAIL) 6526 clearopbeep(cap->oap); 6527 else if ( (cap->oap->op_type == OP_DELETE // only with linewise motions 6528 && cap->oap->motion_force != 'v' 6529 && cap->oap->motion_force != Ctrl_V) 6530 || cap->oap->op_type == OP_LSHIFT 6531 || cap->oap->op_type == OP_RSHIFT) 6532 beginline(BL_SOL | BL_FIX); 6533 else if (cap->oap->op_type != OP_YANK) // 'Y' does not move cursor 6534 beginline(BL_WHITE | BL_FIX); 6535 } 6536 6537 /* 6538 * <Home> command. 6539 */ 6540 static void 6541 nv_home(cmdarg_T *cap) 6542 { 6543 // CTRL-HOME is like "gg" 6544 if (mod_mask & MOD_MASK_CTRL) 6545 nv_goto(cap); 6546 else 6547 { 6548 cap->count0 = 1; 6549 nv_pipe(cap); 6550 } 6551 ins_at_eol = FALSE; // Don't move cursor past eol (only necessary in a 6552 // one-character line). 6553 } 6554 6555 /* 6556 * "|" command. 6557 */ 6558 static void 6559 nv_pipe(cmdarg_T *cap) 6560 { 6561 cap->oap->motion_type = MCHAR; 6562 cap->oap->inclusive = FALSE; 6563 beginline(0); 6564 if (cap->count0 > 0) 6565 { 6566 coladvance((colnr_T)(cap->count0 - 1)); 6567 curwin->w_curswant = (colnr_T)(cap->count0 - 1); 6568 } 6569 else 6570 curwin->w_curswant = 0; 6571 // keep curswant at the column where we wanted to go, not where 6572 // we ended; differs if line is too short 6573 curwin->w_set_curswant = FALSE; 6574 } 6575 6576 /* 6577 * Handle back-word command "b" and "B". 6578 * cap->arg is 1 for "B" 6579 */ 6580 static void 6581 nv_bck_word(cmdarg_T *cap) 6582 { 6583 cap->oap->motion_type = MCHAR; 6584 cap->oap->inclusive = FALSE; 6585 curwin->w_set_curswant = TRUE; 6586 if (bck_word(cap->count1, cap->arg, FALSE) == FAIL) 6587 clearopbeep(cap->oap); 6588 #ifdef FEAT_FOLDING 6589 else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) 6590 foldOpenCursor(); 6591 #endif 6592 } 6593 6594 /* 6595 * Handle word motion commands "e", "E", "w" and "W". 6596 * cap->arg is TRUE for "E" and "W". 6597 */ 6598 static void 6599 nv_wordcmd(cmdarg_T *cap) 6600 { 6601 int n; 6602 int word_end; 6603 int flag = FALSE; 6604 pos_T startpos = curwin->w_cursor; 6605 6606 /* 6607 * Set inclusive for the "E" and "e" command. 6608 */ 6609 if (cap->cmdchar == 'e' || cap->cmdchar == 'E') 6610 word_end = TRUE; 6611 else 6612 word_end = FALSE; 6613 cap->oap->inclusive = word_end; 6614 6615 /* 6616 * "cw" and "cW" are a special case. 6617 */ 6618 if (!word_end && cap->oap->op_type == OP_CHANGE) 6619 { 6620 n = gchar_cursor(); 6621 if (n != NUL) // not an empty line 6622 { 6623 if (VIM_ISWHITE(n)) 6624 { 6625 /* 6626 * Reproduce a funny Vi behaviour: "cw" on a blank only 6627 * changes one character, not all blanks until the start of 6628 * the next word. Only do this when the 'w' flag is included 6629 * in 'cpoptions'. 6630 */ 6631 if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL) 6632 { 6633 cap->oap->inclusive = TRUE; 6634 cap->oap->motion_type = MCHAR; 6635 return; 6636 } 6637 } 6638 else 6639 { 6640 /* 6641 * This is a little strange. To match what the real Vi does, 6642 * we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided 6643 * that we are not on a space or a TAB. This seems impolite 6644 * at first, but it's really more what we mean when we say 6645 * 'cw'. 6646 * Another strangeness: When standing on the end of a word 6647 * "ce" will change until the end of the next word, but "cw" 6648 * will change only one character! This is done by setting 6649 * flag. 6650 */ 6651 cap->oap->inclusive = TRUE; 6652 word_end = TRUE; 6653 flag = TRUE; 6654 } 6655 } 6656 } 6657 6658 cap->oap->motion_type = MCHAR; 6659 curwin->w_set_curswant = TRUE; 6660 if (word_end) 6661 n = end_word(cap->count1, cap->arg, flag, FALSE); 6662 else 6663 n = fwd_word(cap->count1, cap->arg, cap->oap->op_type != OP_NOP); 6664 6665 // Don't leave the cursor on the NUL past the end of line. Unless we 6666 // didn't move it forward. 6667 if (LT_POS(startpos, curwin->w_cursor)) 6668 adjust_cursor(cap->oap); 6669 6670 if (n == FAIL && cap->oap->op_type == OP_NOP) 6671 clearopbeep(cap->oap); 6672 else 6673 { 6674 adjust_for_sel(cap); 6675 #ifdef FEAT_FOLDING 6676 if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) 6677 foldOpenCursor(); 6678 #endif 6679 } 6680 } 6681 6682 /* 6683 * Used after a movement command: If the cursor ends up on the NUL after the 6684 * end of the line, may move it back to the last character and make the motion 6685 * inclusive. 6686 */ 6687 static void 6688 adjust_cursor(oparg_T *oap) 6689 { 6690 // The cursor cannot remain on the NUL when: 6691 // - the column is > 0 6692 // - not in Visual mode or 'selection' is "o" 6693 // - 'virtualedit' is not "all" and not "onemore". 6694 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL 6695 && (!VIsual_active || *p_sel == 'o') 6696 && !virtual_active() && (ve_flags & VE_ONEMORE) == 0) 6697 { 6698 --curwin->w_cursor.col; 6699 // prevent cursor from moving on the trail byte 6700 if (has_mbyte) 6701 mb_adjust_cursor(); 6702 oap->inclusive = TRUE; 6703 } 6704 } 6705 6706 /* 6707 * "0" and "^" commands. 6708 * cap->arg is the argument for beginline(). 6709 */ 6710 static void 6711 nv_beginline(cmdarg_T *cap) 6712 { 6713 cap->oap->motion_type = MCHAR; 6714 cap->oap->inclusive = FALSE; 6715 beginline(cap->arg); 6716 #ifdef FEAT_FOLDING 6717 if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) 6718 foldOpenCursor(); 6719 #endif 6720 ins_at_eol = FALSE; // Don't move cursor past eol (only necessary in a 6721 // one-character line). 6722 } 6723 6724 /* 6725 * In exclusive Visual mode, may include the last character. 6726 */ 6727 static void 6728 adjust_for_sel(cmdarg_T *cap) 6729 { 6730 if (VIsual_active && cap->oap->inclusive && *p_sel == 'e' 6731 && gchar_cursor() != NUL && LT_POS(VIsual, curwin->w_cursor)) 6732 { 6733 if (has_mbyte) 6734 inc_cursor(); 6735 else 6736 ++curwin->w_cursor.col; 6737 cap->oap->inclusive = FALSE; 6738 } 6739 } 6740 6741 /* 6742 * Exclude last character at end of Visual area for 'selection' == "exclusive". 6743 * Should check VIsual_mode before calling this. 6744 * Returns TRUE when backed up to the previous line. 6745 */ 6746 int 6747 unadjust_for_sel(void) 6748 { 6749 pos_T *pp; 6750 6751 if (*p_sel == 'e' && !EQUAL_POS(VIsual, curwin->w_cursor)) 6752 { 6753 if (LT_POS(VIsual, curwin->w_cursor)) 6754 pp = &curwin->w_cursor; 6755 else 6756 pp = &VIsual; 6757 if (pp->coladd > 0) 6758 --pp->coladd; 6759 else 6760 if (pp->col > 0) 6761 { 6762 --pp->col; 6763 mb_adjustpos(curbuf, pp); 6764 } 6765 else if (pp->lnum > 1) 6766 { 6767 --pp->lnum; 6768 pp->col = (colnr_T)STRLEN(ml_get(pp->lnum)); 6769 return TRUE; 6770 } 6771 } 6772 return FALSE; 6773 } 6774 6775 /* 6776 * SELECT key in Normal or Visual mode: end of Select mode mapping. 6777 */ 6778 static void 6779 nv_select(cmdarg_T *cap) 6780 { 6781 if (VIsual_active) 6782 VIsual_select = TRUE; 6783 else if (VIsual_reselect) 6784 { 6785 cap->nchar = 'v'; // fake "gv" command 6786 cap->arg = TRUE; 6787 nv_g_cmd(cap); 6788 } 6789 } 6790 6791 6792 /* 6793 * "G", "gg", CTRL-END, CTRL-HOME. 6794 * cap->arg is TRUE for "G". 6795 */ 6796 static void 6797 nv_goto(cmdarg_T *cap) 6798 { 6799 linenr_T lnum; 6800 6801 if (cap->arg) 6802 lnum = curbuf->b_ml.ml_line_count; 6803 else 6804 lnum = 1L; 6805 cap->oap->motion_type = MLINE; 6806 setpcmark(); 6807 6808 // When a count is given, use it instead of the default lnum 6809 if (cap->count0 != 0) 6810 lnum = cap->count0; 6811 if (lnum < 1L) 6812 lnum = 1L; 6813 else if (lnum > curbuf->b_ml.ml_line_count) 6814 lnum = curbuf->b_ml.ml_line_count; 6815 curwin->w_cursor.lnum = lnum; 6816 beginline(BL_SOL | BL_FIX); 6817 #ifdef FEAT_FOLDING 6818 if ((fdo_flags & FDO_JUMP) && KeyTyped && cap->oap->op_type == OP_NOP) 6819 foldOpenCursor(); 6820 #endif 6821 } 6822 6823 /* 6824 * CTRL-\ in Normal mode. 6825 */ 6826 static void 6827 nv_normal(cmdarg_T *cap) 6828 { 6829 if (cap->nchar == Ctrl_N || cap->nchar == Ctrl_G) 6830 { 6831 clearop(cap->oap); 6832 if (restart_edit != 0 && mode_displayed) 6833 clear_cmdline = TRUE; // unshow mode later 6834 restart_edit = 0; 6835 #ifdef FEAT_CMDWIN 6836 if (cmdwin_type != 0) 6837 cmdwin_result = Ctrl_C; 6838 #endif 6839 if (VIsual_active) 6840 { 6841 end_visual_mode(); // stop Visual 6842 redraw_curbuf_later(INVERTED); 6843 } 6844 // CTRL-\ CTRL-G restarts Insert mode when 'insertmode' is set. 6845 if (cap->nchar == Ctrl_G && p_im) 6846 restart_edit = 'a'; 6847 } 6848 else 6849 clearopbeep(cap->oap); 6850 } 6851 6852 /* 6853 * ESC in Normal mode: beep, but don't flush buffers. 6854 * Don't even beep if we are canceling a command. 6855 */ 6856 static void 6857 nv_esc(cmdarg_T *cap) 6858 { 6859 int no_reason; 6860 6861 no_reason = (cap->oap->op_type == OP_NOP 6862 && cap->opcount == 0 6863 && cap->count0 == 0 6864 && cap->oap->regname == 0 6865 && !p_im); 6866 6867 if (cap->arg) // TRUE for CTRL-C 6868 { 6869 if (restart_edit == 0 6870 #ifdef FEAT_CMDWIN 6871 && cmdwin_type == 0 6872 #endif 6873 && !VIsual_active 6874 && no_reason) 6875 { 6876 if (anyBufIsChanged()) 6877 msg(_("Type :qa! and press <Enter> to abandon all changes and exit Vim")); 6878 else 6879 msg(_("Type :qa and press <Enter> to exit Vim")); 6880 } 6881 6882 // Don't reset "restart_edit" when 'insertmode' is set, it won't be 6883 // set again below when halfway a mapping. 6884 if (!p_im) 6885 restart_edit = 0; 6886 #ifdef FEAT_CMDWIN 6887 if (cmdwin_type != 0) 6888 { 6889 cmdwin_result = K_IGNORE; 6890 got_int = FALSE; // don't stop executing autocommands et al. 6891 return; 6892 } 6893 #endif 6894 } 6895 6896 if (VIsual_active) 6897 { 6898 end_visual_mode(); // stop Visual 6899 check_cursor_col(); // make sure cursor is not beyond EOL 6900 curwin->w_set_curswant = TRUE; 6901 redraw_curbuf_later(INVERTED); 6902 } 6903 else if (no_reason) 6904 vim_beep(BO_ESC); 6905 clearop(cap->oap); 6906 6907 // A CTRL-C is often used at the start of a menu. When 'insertmode' is 6908 // set return to Insert mode afterwards. 6909 if (restart_edit == 0 && goto_im() && ex_normal_busy == 0) 6910 restart_edit = 'a'; 6911 } 6912 6913 /* 6914 * Move the cursor for the "A" command. 6915 */ 6916 void 6917 set_cursor_for_append_to_line(void) 6918 { 6919 curwin->w_set_curswant = TRUE; 6920 if (ve_flags == VE_ALL) 6921 { 6922 int save_State = State; 6923 6924 // Pretend Insert mode here to allow the cursor on the 6925 // character past the end of the line 6926 State = INSERT; 6927 coladvance((colnr_T)MAXCOL); 6928 State = save_State; 6929 } 6930 else 6931 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor()); 6932 } 6933 6934 /* 6935 * Handle "A", "a", "I", "i" and <Insert> commands. 6936 * Also handle K_PS, start bracketed paste. 6937 */ 6938 static void 6939 nv_edit(cmdarg_T *cap) 6940 { 6941 // <Insert> is equal to "i" 6942 if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS) 6943 cap->cmdchar = 'i'; 6944 6945 // in Visual mode "A" and "I" are an operator 6946 if (VIsual_active && (cap->cmdchar == 'A' || cap->cmdchar == 'I')) 6947 { 6948 #ifdef FEAT_TERMINAL 6949 if (term_in_normal_mode()) 6950 { 6951 end_visual_mode(); 6952 clearop(cap->oap); 6953 term_enter_job_mode(); 6954 return; 6955 } 6956 #endif 6957 v_visop(cap); 6958 } 6959 6960 // in Visual mode and after an operator "a" and "i" are for text objects 6961 else if ((cap->cmdchar == 'a' || cap->cmdchar == 'i') 6962 && (cap->oap->op_type != OP_NOP || VIsual_active)) 6963 { 6964 #ifdef FEAT_TEXTOBJ 6965 nv_object(cap); 6966 #else 6967 clearopbeep(cap->oap); 6968 #endif 6969 } 6970 #ifdef FEAT_TERMINAL 6971 else if (term_in_normal_mode()) 6972 { 6973 clearop(cap->oap); 6974 term_enter_job_mode(); 6975 return; 6976 } 6977 #endif 6978 else if (!curbuf->b_p_ma && !p_im) 6979 { 6980 // Only give this error when 'insertmode' is off. 6981 emsg(_(e_modifiable)); 6982 clearop(cap->oap); 6983 if (cap->cmdchar == K_PS) 6984 // drop the pasted text 6985 bracketed_paste(PASTE_INSERT, TRUE, NULL); 6986 } 6987 else if (cap->cmdchar == K_PS && VIsual_active) 6988 { 6989 pos_T old_pos = curwin->w_cursor; 6990 pos_T old_visual = VIsual; 6991 6992 // In Visual mode the selected text is deleted. 6993 if (VIsual_mode == 'V' || curwin->w_cursor.lnum != VIsual.lnum) 6994 { 6995 shift_delete_registers(); 6996 cap->oap->regname = '1'; 6997 } 6998 else 6999 cap->oap->regname = '-'; 7000 cap->cmdchar = 'd'; 7001 cap->nchar = NUL; 7002 nv_operator(cap); 7003 do_pending_operator(cap, 0, FALSE); 7004 cap->cmdchar = K_PS; 7005 7006 // When the last char in the line was deleted then append. Detect this 7007 // by checking if the cursor moved to before the Visual area. 7008 if (*ml_get_cursor() != NUL && LT_POS(curwin->w_cursor, old_pos) 7009 && LT_POS(curwin->w_cursor, old_visual)) 7010 inc_cursor(); 7011 7012 // Insert to replace the deleted text with the pasted text. 7013 invoke_edit(cap, FALSE, cap->cmdchar, FALSE); 7014 } 7015 else if (!checkclearopq(cap->oap)) 7016 { 7017 switch (cap->cmdchar) 7018 { 7019 case 'A': // "A"ppend after the line 7020 set_cursor_for_append_to_line(); 7021 break; 7022 7023 case 'I': // "I"nsert before the first non-blank 7024 if (vim_strchr(p_cpo, CPO_INSEND) == NULL) 7025 beginline(BL_WHITE); 7026 else 7027 beginline(BL_WHITE|BL_FIX); 7028 break; 7029 7030 case K_PS: 7031 // Bracketed paste works like "a"ppend, unless the cursor is in 7032 // the first column, then it inserts. 7033 if (curwin->w_cursor.col == 0) 7034 break; 7035 // FALLTHROUGH 7036 7037 case 'a': // "a"ppend is like "i"nsert on the next character. 7038 // increment coladd when in virtual space, increment the 7039 // column otherwise, also to append after an unprintable char 7040 if (virtual_active() 7041 && (curwin->w_cursor.coladd > 0 7042 || *ml_get_cursor() == NUL 7043 || *ml_get_cursor() == TAB)) 7044 curwin->w_cursor.coladd++; 7045 else if (*ml_get_cursor() != NUL) 7046 inc_cursor(); 7047 break; 7048 } 7049 7050 if (curwin->w_cursor.coladd && cap->cmdchar != 'A') 7051 { 7052 int save_State = State; 7053 7054 // Pretend Insert mode here to allow the cursor on the 7055 // character past the end of the line 7056 State = INSERT; 7057 coladvance(getviscol()); 7058 State = save_State; 7059 } 7060 7061 invoke_edit(cap, FALSE, cap->cmdchar, FALSE); 7062 } 7063 else if (cap->cmdchar == K_PS) 7064 // drop the pasted text 7065 bracketed_paste(PASTE_INSERT, TRUE, NULL); 7066 } 7067 7068 /* 7069 * Invoke edit() and take care of "restart_edit" and the return value. 7070 */ 7071 static void 7072 invoke_edit( 7073 cmdarg_T *cap, 7074 int repl, // "r" or "gr" command 7075 int cmd, 7076 int startln) 7077 { 7078 int restart_edit_save = 0; 7079 7080 // Complicated: When the user types "a<C-O>a" we don't want to do Insert 7081 // mode recursively. But when doing "a<C-O>." or "a<C-O>rx" we do allow 7082 // it. 7083 if (repl || !stuff_empty()) 7084 restart_edit_save = restart_edit; 7085 else 7086 restart_edit_save = 0; 7087 7088 // Always reset "restart_edit", this is not a restarted edit. 7089 restart_edit = 0; 7090 7091 if (edit(cmd, startln, cap->count1)) 7092 cap->retval |= CA_COMMAND_BUSY; 7093 7094 if (restart_edit == 0) 7095 restart_edit = restart_edit_save; 7096 } 7097 7098 #ifdef FEAT_TEXTOBJ 7099 /* 7100 * "a" or "i" while an operator is pending or in Visual mode: object motion. 7101 */ 7102 static void 7103 nv_object( 7104 cmdarg_T *cap) 7105 { 7106 int flag; 7107 int include; 7108 char_u *mps_save; 7109 7110 if (cap->cmdchar == 'i') 7111 include = FALSE; // "ix" = inner object: exclude white space 7112 else 7113 include = TRUE; // "ax" = an object: include white space 7114 7115 // Make sure (), [], {} and <> are in 'matchpairs' 7116 mps_save = curbuf->b_p_mps; 7117 curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>"; 7118 7119 switch (cap->nchar) 7120 { 7121 case 'w': // "aw" = a word 7122 flag = current_word(cap->oap, cap->count1, include, FALSE); 7123 break; 7124 case 'W': // "aW" = a WORD 7125 flag = current_word(cap->oap, cap->count1, include, TRUE); 7126 break; 7127 case 'b': // "ab" = a braces block 7128 case '(': 7129 case ')': 7130 flag = current_block(cap->oap, cap->count1, include, '(', ')'); 7131 break; 7132 case 'B': // "aB" = a Brackets block 7133 case '{': 7134 case '}': 7135 flag = current_block(cap->oap, cap->count1, include, '{', '}'); 7136 break; 7137 case '[': // "a[" = a [] block 7138 case ']': 7139 flag = current_block(cap->oap, cap->count1, include, '[', ']'); 7140 break; 7141 case '<': // "a<" = a <> block 7142 case '>': 7143 flag = current_block(cap->oap, cap->count1, include, '<', '>'); 7144 break; 7145 case 't': // "at" = a tag block (xml and html) 7146 // Do not adjust oap->end in do_pending_operator() 7147 // otherwise there are different results for 'dit' 7148 // (note leading whitespace in last line): 7149 // 1) <b> 2) <b> 7150 // foobar foobar 7151 // </b> </b> 7152 cap->retval |= CA_NO_ADJ_OP_END; 7153 flag = current_tagblock(cap->oap, cap->count1, include); 7154 break; 7155 case 'p': // "ap" = a paragraph 7156 flag = current_par(cap->oap, cap->count1, include, 'p'); 7157 break; 7158 case 's': // "as" = a sentence 7159 flag = current_sent(cap->oap, cap->count1, include); 7160 break; 7161 case '"': // "a"" = a double quoted string 7162 case '\'': // "a'" = a single quoted string 7163 case '`': // "a`" = a backtick quoted string 7164 flag = current_quote(cap->oap, cap->count1, include, 7165 cap->nchar); 7166 break; 7167 #if 0 // TODO 7168 case 'S': // "aS" = a section 7169 case 'f': // "af" = a filename 7170 case 'u': // "au" = a URL 7171 #endif 7172 default: 7173 flag = FAIL; 7174 break; 7175 } 7176 7177 curbuf->b_p_mps = mps_save; 7178 if (flag == FAIL) 7179 clearopbeep(cap->oap); 7180 adjust_cursor_col(); 7181 curwin->w_set_curswant = TRUE; 7182 } 7183 #endif 7184 7185 /* 7186 * "q" command: Start/stop recording. 7187 * "q:", "q/", "q?": edit command-line in command-line window. 7188 */ 7189 static void 7190 nv_record(cmdarg_T *cap) 7191 { 7192 if (cap->oap->op_type == OP_FORMAT) 7193 { 7194 // "gqq" is the same as "gqgq": format line 7195 cap->cmdchar = 'g'; 7196 cap->nchar = 'q'; 7197 nv_operator(cap); 7198 } 7199 else if (!checkclearop(cap->oap)) 7200 { 7201 #ifdef FEAT_CMDWIN 7202 if (cap->nchar == ':' || cap->nchar == '/' || cap->nchar == '?') 7203 { 7204 stuffcharReadbuff(cap->nchar); 7205 stuffcharReadbuff(K_CMDWIN); 7206 } 7207 else 7208 #endif 7209 // (stop) recording into a named register, unless executing a 7210 // register 7211 if (reg_executing == 0 && do_record(cap->nchar) == FAIL) 7212 clearopbeep(cap->oap); 7213 } 7214 } 7215 7216 /* 7217 * Handle the "@r" command. 7218 */ 7219 static void 7220 nv_at(cmdarg_T *cap) 7221 { 7222 if (checkclearop(cap->oap)) 7223 return; 7224 #ifdef FEAT_EVAL 7225 if (cap->nchar == '=') 7226 { 7227 if (get_expr_register() == NUL) 7228 return; 7229 } 7230 #endif 7231 while (cap->count1-- && !got_int) 7232 { 7233 if (do_execreg(cap->nchar, FALSE, FALSE, FALSE) == FAIL) 7234 { 7235 clearopbeep(cap->oap); 7236 break; 7237 } 7238 line_breakcheck(); 7239 } 7240 } 7241 7242 /* 7243 * Handle the CTRL-U and CTRL-D commands. 7244 */ 7245 static void 7246 nv_halfpage(cmdarg_T *cap) 7247 { 7248 if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1) 7249 || (cap->cmdchar == Ctrl_D 7250 && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)) 7251 clearopbeep(cap->oap); 7252 else if (!checkclearop(cap->oap)) 7253 halfpage(cap->cmdchar == Ctrl_D, cap->count0); 7254 } 7255 7256 /* 7257 * Handle "J" or "gJ" command. 7258 */ 7259 static void 7260 nv_join(cmdarg_T *cap) 7261 { 7262 if (VIsual_active) // join the visual lines 7263 nv_operator(cap); 7264 else if (!checkclearop(cap->oap)) 7265 { 7266 if (cap->count0 <= 1) 7267 cap->count0 = 2; // default for join is two lines! 7268 if (curwin->w_cursor.lnum + cap->count0 - 1 > 7269 curbuf->b_ml.ml_line_count) 7270 { 7271 // can't join when on the last line 7272 if (cap->count0 <= 2) 7273 { 7274 clearopbeep(cap->oap); 7275 return; 7276 } 7277 cap->count0 = curbuf->b_ml.ml_line_count 7278 - curwin->w_cursor.lnum + 1; 7279 } 7280 7281 prep_redo(cap->oap->regname, cap->count0, 7282 NUL, cap->cmdchar, NUL, NUL, cap->nchar); 7283 (void)do_join(cap->count0, cap->nchar == NUL, TRUE, TRUE, TRUE); 7284 } 7285 } 7286 7287 /* 7288 * "P", "gP", "p" and "gp" commands. 7289 */ 7290 static void 7291 nv_put(cmdarg_T *cap) 7292 { 7293 nv_put_opt(cap, FALSE); 7294 } 7295 7296 /* 7297 * "P", "gP", "p" and "gp" commands. 7298 * "fix_indent" is TRUE for "[p", "[P", "]p" and "]P". 7299 */ 7300 static void 7301 nv_put_opt(cmdarg_T *cap, int fix_indent) 7302 { 7303 int regname = 0; 7304 void *reg1 = NULL, *reg2 = NULL; 7305 int empty = FALSE; 7306 int was_visual = FALSE; 7307 int dir; 7308 int flags = 0; 7309 7310 if (cap->oap->op_type != OP_NOP) 7311 { 7312 #ifdef FEAT_DIFF 7313 // "dp" is ":diffput" 7314 if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'p') 7315 { 7316 clearop(cap->oap); 7317 nv_diffgetput(TRUE, cap->opcount); 7318 } 7319 else 7320 #endif 7321 clearopbeep(cap->oap); 7322 } 7323 #ifdef FEAT_JOB_CHANNEL 7324 else if (bt_prompt(curbuf) && !prompt_curpos_editable()) 7325 { 7326 clearopbeep(cap->oap); 7327 } 7328 #endif 7329 else 7330 { 7331 if (fix_indent) 7332 { 7333 dir = (cap->cmdchar == ']' && cap->nchar == 'p') 7334 ? FORWARD : BACKWARD; 7335 flags |= PUT_FIXINDENT; 7336 } 7337 else 7338 dir = (cap->cmdchar == 'P' 7339 || (cap->cmdchar == 'g' && cap->nchar == 'P')) 7340 ? BACKWARD : FORWARD; 7341 prep_redo_cmd(cap); 7342 if (cap->cmdchar == 'g') 7343 flags |= PUT_CURSEND; 7344 7345 if (VIsual_active) 7346 { 7347 // Putting in Visual mode: The put text replaces the selected 7348 // text. First delete the selected text, then put the new text. 7349 // Need to save and restore the registers that the delete 7350 // overwrites if the old contents is being put. 7351 was_visual = TRUE; 7352 regname = cap->oap->regname; 7353 #ifdef FEAT_CLIPBOARD 7354 adjust_clip_reg(®name); 7355 #endif 7356 if (regname == 0 || regname == '"' 7357 || VIM_ISDIGIT(regname) || regname == '-' 7358 #ifdef FEAT_CLIPBOARD 7359 || (clip_unnamed && (regname == '*' || regname == '+')) 7360 #endif 7361 7362 ) 7363 { 7364 // The delete is going to overwrite the register we want to 7365 // put, save it first. 7366 reg1 = get_register(regname, TRUE); 7367 } 7368 7369 // Now delete the selected text. Avoid messages here. 7370 cap->cmdchar = 'd'; 7371 cap->nchar = NUL; 7372 cap->oap->regname = NUL; 7373 ++msg_silent; 7374 nv_operator(cap); 7375 do_pending_operator(cap, 0, FALSE); 7376 empty = (curbuf->b_ml.ml_flags & ML_EMPTY); 7377 --msg_silent; 7378 7379 // delete PUT_LINE_BACKWARD; 7380 cap->oap->regname = regname; 7381 7382 if (reg1 != NULL) 7383 { 7384 // Delete probably changed the register we want to put, save 7385 // it first. Then put back what was there before the delete. 7386 reg2 = get_register(regname, FALSE); 7387 put_register(regname, reg1); 7388 } 7389 7390 // When deleted a linewise Visual area, put the register as 7391 // lines to avoid it joined with the next line. When deletion was 7392 // characterwise, split a line when putting lines. 7393 if (VIsual_mode == 'V') 7394 flags |= PUT_LINE; 7395 else if (VIsual_mode == 'v') 7396 flags |= PUT_LINE_SPLIT; 7397 if (VIsual_mode == Ctrl_V && dir == FORWARD) 7398 flags |= PUT_LINE_FORWARD; 7399 dir = BACKWARD; 7400 if ((VIsual_mode != 'V' 7401 && curwin->w_cursor.col < curbuf->b_op_start.col) 7402 || (VIsual_mode == 'V' 7403 && curwin->w_cursor.lnum < curbuf->b_op_start.lnum)) 7404 // cursor is at the end of the line or end of file, put 7405 // forward. 7406 dir = FORWARD; 7407 // May have been reset in do_put(). 7408 VIsual_active = TRUE; 7409 } 7410 do_put(cap->oap->regname, dir, cap->count1, flags); 7411 7412 // If a register was saved, put it back now. 7413 if (reg2 != NULL) 7414 put_register(regname, reg2); 7415 7416 // What to reselect with "gv"? Selecting the just put text seems to 7417 // be the most useful, since the original text was removed. 7418 if (was_visual) 7419 { 7420 curbuf->b_visual.vi_start = curbuf->b_op_start; 7421 curbuf->b_visual.vi_end = curbuf->b_op_end; 7422 // need to adjust cursor position 7423 if (*p_sel == 'e') 7424 inc(&curbuf->b_visual.vi_end); 7425 } 7426 7427 // When all lines were selected and deleted do_put() leaves an empty 7428 // line that needs to be deleted now. 7429 if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) 7430 { 7431 ml_delete_flags(curbuf->b_ml.ml_line_count, ML_DEL_MESSAGE); 7432 deleted_lines(curbuf->b_ml.ml_line_count + 1, 1); 7433 7434 // If the cursor was in that line, move it to the end of the last 7435 // line. 7436 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 7437 { 7438 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 7439 coladvance((colnr_T)MAXCOL); 7440 } 7441 } 7442 auto_format(FALSE, TRUE); 7443 } 7444 } 7445 7446 /* 7447 * "o" and "O" commands. 7448 */ 7449 static void 7450 nv_open(cmdarg_T *cap) 7451 { 7452 #ifdef FEAT_DIFF 7453 // "do" is ":diffget" 7454 if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'o') 7455 { 7456 clearop(cap->oap); 7457 nv_diffgetput(FALSE, cap->opcount); 7458 } 7459 else 7460 #endif 7461 if (VIsual_active) // switch start and end of visual 7462 v_swap_corners(cap->cmdchar); 7463 #ifdef FEAT_JOB_CHANNEL 7464 else if (bt_prompt(curbuf)) 7465 clearopbeep(cap->oap); 7466 #endif 7467 else 7468 n_opencmd(cap); 7469 } 7470 7471 #ifdef FEAT_NETBEANS_INTG 7472 static void 7473 nv_nbcmd(cmdarg_T *cap) 7474 { 7475 netbeans_keycommand(cap->nchar); 7476 } 7477 #endif 7478 7479 #ifdef FEAT_DND 7480 static void 7481 nv_drop(cmdarg_T *cap UNUSED) 7482 { 7483 do_put('~', BACKWARD, 1L, PUT_CURSEND); 7484 } 7485 #endif 7486 7487 /* 7488 * Trigger CursorHold event. 7489 * When waiting for a character for 'updatetime' K_CURSORHOLD is put in the 7490 * input buffer. "did_cursorhold" is set to avoid retriggering. 7491 */ 7492 static void 7493 nv_cursorhold(cmdarg_T *cap) 7494 { 7495 apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, FALSE, curbuf); 7496 did_cursorhold = TRUE; 7497 cap->retval |= CA_COMMAND_BUSY; // don't call edit() now 7498 } 7499