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