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