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