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