normal.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:125k
源码类别:

编辑器/阅读器

开发平台:

DOS

  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.  */
  8. /*
  9.  * Contains the main routine for processing characters in command mode.
  10.  * Communicates closely with the code in ops.c to handle the operators.
  11.  */
  12. #include "vim.h"
  13. /*
  14.  * The Visual area is remembered for reselection.
  15.  */
  16. static int resel_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
  17. static linenr_t resel_VIsual_line_count; /* number of lines */
  18. static colnr_t resel_VIsual_col; /* nr of cols or end col */
  19. /*
  20.  * Operator characters; The order must correspond to the defines in vim.h!
  21.  */
  22. static char_u *op_chars = (char_u *)"dyc<>!~=q:UuJ";
  23. static void op_colon __ARGS((OPARG *oap));
  24. #ifdef USE_MOUSE
  25. static void find_start_of_word __ARGS((FPOS *));
  26. static void find_end_of_word __ARGS((FPOS *));
  27. static int get_mouse_class __ARGS((int));
  28. #endif
  29. static void prep_redo_cmd __ARGS((CMDARG *cap));
  30. static void prep_redo __ARGS((int regname, long, int, int, int, int));
  31. static int checkclearop __ARGS((OPARG *oap));
  32. static int checkclearopq __ARGS((OPARG *oap));
  33. static void clearop __ARGS((OPARG *oap));
  34. static void clearopbeep __ARGS((OPARG *oap));
  35. #ifdef SHOWCMD
  36. static void del_from_showcmd __ARGS((int));
  37. #endif
  38. /*
  39.  * nv_*(): functions called to handle Normal and Visual mode commands.
  40.  * n_*(): functions called to handle Normal mode commands.
  41.  * v_*(): functions called to handle Visual mode commands.
  42.  */
  43. static void nv_gd __ARGS((OPARG *oap, int nchar));
  44. static int nv_screengo __ARGS((OPARG *oap, int dir, long dist));
  45. static void nv_scroll_line __ARGS((CMDARG *cap, int is_ctrl_e));
  46. static void nv_zet __ARGS((CMDARG *cap));
  47. static void nv_colon __ARGS((CMDARG *cap));
  48. static void nv_ctrlg __ARGS((CMDARG *cap));
  49. static void nv_zzet __ARGS((CMDARG *cap));
  50. static void nv_ident __ARGS((CMDARG *cap, char_u **searchp));
  51. static void nv_scroll __ARGS((CMDARG *cap));
  52. static void nv_right __ARGS((CMDARG *cap));
  53. static int nv_left __ARGS((CMDARG *cap));
  54. #ifdef FILE_IN_PATH
  55. static void nv_gotofile __ARGS((CMDARG *cap));
  56. #endif
  57. static void nv_search __ARGS((CMDARG *cap, char_u **searchp, int dont_set_mark));
  58. static void nv_next __ARGS((CMDARG *cap, int flag));
  59. static void nv_csearch __ARGS((CMDARG *cap, int dir, int type));
  60. static void nv_brackets __ARGS((CMDARG *cap, int dir));
  61. static void nv_percent __ARGS((CMDARG *cap));
  62. static void nv_brace __ARGS((CMDARG *cap, int dir));
  63. static int n_replace __ARGS((CMDARG *cap));
  64. static void v_swap_corners __ARGS((CMDARG *cap));
  65. static int nv_replace __ARGS((CMDARG *cap));
  66. static void n_swapchar __ARGS((CMDARG *cap));
  67. static void nv_cursormark __ARGS((CMDARG *cap, int flag, FPOS *pos));
  68. static void v_visop __ARGS((CMDARG *cap));
  69. static void nv_optrans __ARGS((CMDARG *cap));
  70. static void nv_gomark __ARGS((CMDARG *cap, int flag));
  71. static void nv_pcmark __ARGS((CMDARG *cap));
  72. static void nv_regname __ARGS((CMDARG *cap, linenr_t *opnump));
  73. static void nv_visual __ARGS((CMDARG *cap, int selectmode));
  74. static void n_start_visual_mode __ARGS((int c));
  75. static int nv_g_cmd __ARGS((CMDARG *cap, char_u **searchp));
  76. static int n_opencmd __ARGS((CMDARG *cap));
  77. static void nv_Undo __ARGS((CMDARG *cap));
  78. static void nv_operator __ARGS((CMDARG *cap));
  79. static void nv_lineop __ARGS((CMDARG *cap));
  80. static void nv_pipe __ARGS((CMDARG *cap));
  81. static void nv_bck_word __ARGS((CMDARG *cap, int type));
  82. static void nv_wordcmd __ARGS((CMDARG *cap, int type));
  83. static void adjust_for_sel __ARGS((CMDARG *cap));
  84. static void nv_goto __ARGS((OPARG *oap, long lnum));
  85. static void nv_select __ARGS((CMDARG *cap));
  86. static void nv_esc __ARGS((CMDARG *oap, linenr_t opnum));
  87. static int nv_append __ARGS((CMDARG *cap));
  88. #ifdef TEXT_OBJECTS
  89. static void nv_object __ARGS((CMDARG *cap));
  90. #endif
  91. static void nv_at __ARGS((CMDARG *cap));
  92. static void nv_halfpage __ARGS((CMDARG *cap));
  93. static void nv_join __ARGS((CMDARG *cap));
  94. static void nv_put __ARGS((CMDARG *cap));
  95. /*
  96.  * normal
  97.  *
  98.  * Execute a command in Normal mode.
  99.  *
  100.  * This is basically a big switch with the cases arranged in rough categories
  101.  * in the following order:
  102.  *
  103.  *    0. Macros (q, @)
  104.  *    1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
  105.  *    2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
  106.  *    3. Cursor motions (G, H, M, L, l, K_RIGHT,  , h, K_LEFT, ^H, k, K_UP,
  107.  *  ^P, +, CR, LF, j, K_DOWN, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
  108.  *    4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
  109.  *    5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
  110.  *    6. Inserts (A, a, I, i, o, O, R)
  111.  *    7. Operators (~, d, c, y, >, <, !, =)
  112.  *    8. Abbreviations (x, X, D, C, s, S, Y, &)
  113.  *    9. Marks (m, ', `, ^O, ^I)
  114.  *   10. Register name setting ('"')
  115.  *   11. Visual (v, V, ^V)
  116.  *   12. Suspend (^Z)
  117.  *   13. Window commands (^W)
  118.  *   14. extended commands (starting with 'g')
  119.  *   15. mouse click
  120.  *   16. scrollbar movement
  121.  *   17. The end (ESC)
  122.  */
  123.     void
  124. normal_cmd(oap, toplevel)
  125.     OPARG *oap;
  126.     int toplevel; /* TRUE when called from main() */
  127. {
  128.     static linenr_t opnum = 0;     /* count before an operator */
  129.     CMDARG     ca;     /* command arguments */
  130.     int     c;
  131.     int     flag = FALSE;
  132.     int     type = 0;     /* type of operation */
  133.     int     dir = FORWARD;     /* search direction */
  134.     char_u     *searchbuff = NULL;     /* buffer for search string */
  135.     int     command_busy = FALSE;
  136.     int     ctrl_w = FALSE;     /* got CTRL-W command */
  137.     int     old_col = curwin->w_curswant;
  138.     int     dont_adjust_op_end = FALSE;
  139.     FPOS     old_pos;     /* cursor position before command */
  140. #ifdef SHOWCMD
  141.     int     need_flushbuf;     /* need to call out_flush() */
  142. #endif
  143.     static int     restart_VIsual_select = 0;
  144.     int     mapped_len;
  145.     static int     old_mapped_len = 0;
  146.     vim_memset(&ca, 0, sizeof(ca));
  147.     ca.oap = oap;
  148. #ifdef USE_SNIFF
  149.     want_sniff_request = sniff_connected;
  150. #endif
  151.     /*
  152.      * If there is an operator pending, then the command we take this time
  153.      * will terminate it. Finish_op tells us to finish the operation before
  154.      * returning this time (unless the operation was cancelled).
  155.      */
  156. #ifdef CURSOR_SHAPE
  157.     c = finish_op;
  158. #endif
  159.     finish_op = (oap->op_type != OP_NOP);
  160. #ifdef CURSOR_SHAPE
  161.     if (finish_op != c)
  162. ui_cursor_shape(); /* may show different cursor shape */
  163. #endif
  164.     if (!finish_op && !oap->regname)
  165. opnum = 0;
  166.     mapped_len = typebuf_maplen();
  167.     State = NORMAL_BUSY;
  168. #ifdef USE_GUI_WIN32
  169.     dont_scroll = FALSE; /* allow scrolling here */
  170. #endif
  171.     c = vgetc();
  172. #ifdef HAVE_LANGMAP
  173.     LANGMAP_ADJUST(c, TRUE);
  174. #endif
  175.     /*
  176.      * If a mapping was started in Visual or Select mode, remember the length
  177.      * of the mapping.  This is used below to not return to Insert mode for as
  178.      * long as the mapping is being executed.
  179.      */
  180.     if (!restart_edit)
  181. old_mapped_len = 0;
  182.     else if (old_mapped_len
  183.     || (VIsual_active && mapped_len == 0 && typebuf_maplen() > 0))
  184. old_mapped_len = typebuf_maplen();
  185.     if (c == NUL)
  186. c = K_ZERO;
  187.     else if (c == K_KMULTIPLY)  /* K_KMULTIPLY is same as '*' */
  188. c = '*';
  189.     else if (c == K_KMINUS) /* K_KMINUS is same as '-' */
  190. c = '-';
  191.     else if (c == K_KPLUS) /* K_KPLUS is same as '+' */
  192. c = '+';
  193.     else if (c == K_KDIVIDE) /* K_KDIVIDE is same as '/' */
  194. c = '/';
  195.     /*
  196.      * In Visual/Select mode, a few keys are handled in a special way.
  197.      */
  198.     if (VIsual_active)
  199.     {
  200. /* In Select mode, typed text replaces the selection */
  201. if (VIsual_select)
  202. {
  203.     if (vim_isprintc(c) || c == NL || c == CR || c == K_KENTER)
  204.     {
  205. stuffcharReadbuff(c);
  206. c = 'c';
  207.     }
  208. }
  209. /* when 'keymode' contains "stopsel" may stop Select/Visual mode */
  210. if (vim_strchr(p_km, 'o') != NULL)
  211. {
  212.     switch (c)
  213.     {
  214. case K_UP:
  215. case Ctrl('P'):
  216. case K_DOWN:
  217. case Ctrl('N'):
  218. case K_LEFT:
  219. case K_RIGHT:
  220. case Ctrl('B'):
  221. case K_PAGEUP:
  222. case K_KPAGEUP:
  223. case Ctrl('F'):
  224. case K_PAGEDOWN:
  225. case K_KPAGEDOWN:
  226. case K_HOME:
  227. case K_KHOME:
  228. case K_END:
  229. case K_KEND:
  230.     if (!(mod_mask & MOD_MASK_SHIFT))
  231.     {
  232. end_visual_mode();
  233. redraw_curbuf_later(NOT_VALID);
  234.     }
  235.     break;
  236.     }
  237. }
  238. /* Keys that work different when 'keymode' contains "startsel" */
  239. if (vim_strchr(p_km, 'a') != NULL)
  240. {
  241.     switch (c)
  242.     {
  243. case K_S_UP: c = K_UP; break;
  244. case K_S_DOWN: c = K_DOWN; break;
  245. case K_S_LEFT: c = K_LEFT; break;
  246. case K_S_RIGHT: c = K_RIGHT; break;
  247. case K_S_HOME: c = K_HOME; break;
  248. case K_S_END: c = K_END; break;
  249. case K_PAGEUP:
  250. case K_KPAGEUP:
  251. case K_PAGEDOWN:
  252. case K_KPAGEDOWN:
  253. case K_KHOME:
  254. case K_KEND:
  255. mod_mask &= !MOD_MASK_SHIFT; break;
  256.     }
  257. }
  258.     }
  259. #ifdef SHOWCMD
  260.     need_flushbuf = add_to_showcmd(c);
  261. #endif
  262. getcount:
  263.     if (!(VIsual_active && VIsual_select))
  264.     {
  265. /* Pick up any leading digits and compute ca.count0 */
  266. while (    (c >= '1' && c <= '9')
  267. || (ca.count0 != 0 && (c == K_DEL || c == '0')))
  268. {
  269.     if (c == K_DEL)
  270.     {
  271. ca.count0 /= 10;
  272. #ifdef SHOWCMD
  273. del_from_showcmd(4); /* delete the digit and ~@% */
  274. #endif
  275.     }
  276.     else
  277. ca.count0 = ca.count0 * 10 + (c - '0');
  278.     if (ca.count0 < 0)     /* got too large! */
  279. ca.count0 = 999999999;
  280.     if (ctrl_w)
  281.     {
  282. ++no_mapping;
  283. ++allow_keys; /* no mapping for nchar, but keys */
  284.     }
  285.     c = vgetc();
  286. #ifdef HAVE_LANGMAP
  287.     LANGMAP_ADJUST(c, TRUE);
  288. #endif
  289.     if (ctrl_w)
  290.     {
  291. --no_mapping;
  292. --allow_keys;
  293.     }
  294. #ifdef SHOWCMD
  295.     need_flushbuf |= add_to_showcmd(c);
  296. #endif
  297. }
  298.     /*
  299.      * If we got CTRL-W there may be a/another count
  300.      */
  301. if (c == Ctrl('W') && !ctrl_w && oap->op_type == OP_NOP)
  302. {
  303.     ctrl_w = TRUE;
  304.     opnum = ca.count0; /* remember first count */
  305.     ca.count0 = 0;
  306.     ++no_mapping;
  307.     ++allow_keys; /* no mapping for nchar, but keys */
  308.     c = vgetc(); /* get next character */
  309. #ifdef HAVE_LANGMAP
  310.     LANGMAP_ADJUST(c, TRUE);
  311. #endif
  312.     --no_mapping;
  313.     --allow_keys;
  314. #ifdef SHOWCMD
  315.     need_flushbuf |= add_to_showcmd(c);
  316. #endif
  317.     goto getcount; /* jump back */
  318. }
  319.     }
  320.     ca.cmdchar = c;
  321.     /*
  322.      * If we're in the middle of an operator (including after entering a yank
  323.      * buffer with '"') AND we had a count before the
  324.      * operator, then that count overrides the current value of ca.count0.
  325.      * What * this means effectively, is that commands like "3dw" get turned
  326.      * into "d3w" which makes things fall into place pretty neatly.
  327.      * If you give a count before AND after the operator, they are multiplied.
  328.      */
  329.     if (opnum != 0)
  330.     {
  331.     if (ca.count0)
  332. ca.count0 *= opnum;
  333.     else
  334. ca.count0 = opnum;
  335.     }
  336.     /*
  337.      * Always remember the count.  It will be set to zero (on the next call,
  338.      * above) when there is no pending operator.
  339.      * When called from main(), save the count for use by the "count" built-in
  340.      * variable.
  341.      */
  342.     opnum = ca.count0;
  343.     if (toplevel)
  344. global_opnum = opnum;
  345.     ca.count1 = (ca.count0 == 0 ? 1 : ca.count0);
  346.     /*
  347.      * Get an additional character if we need one.
  348.      * For CTRL-W we already got it when looking for a count.
  349.      */
  350.     if (ctrl_w)
  351.     {
  352. ca.nchar = ca.cmdchar;
  353. ca.cmdchar = Ctrl('W');
  354.     }
  355.     else if ( (oap->op_type == OP_NOP
  356. && vim_strchr((char_u *)"@zm"", ca.cmdchar) != NULL)
  357.     || (oap->op_type == OP_NOP
  358. && !VIsual_active
  359. && (ca.cmdchar == 'r' || ca.cmdchar == 'Z'))
  360.     || vim_strchr((char_u *)"tTfF[]g'`", ca.cmdchar) != NULL
  361.     || (ca.cmdchar == 'q'
  362. && oap->op_type == OP_NOP
  363. && !Recording
  364. && !Exec_reg)
  365.     || ((ca.cmdchar == 'a' || ca.cmdchar == 'i')
  366. && (oap->op_type != OP_NOP || VIsual_active)))
  367.     {
  368. ++no_mapping;
  369. ++allow_keys; /* no mapping for nchar, but allow key codes */
  370. #ifdef CURSOR_SHAPE
  371. if (ca.cmdchar == 'r')
  372. {
  373.     State = REPLACE; /* pretend Replace mode, for cursor shape */
  374.     ui_cursor_shape(); /* show different cursor shape */
  375. }
  376. #endif
  377. ca.nchar = vgetc();
  378. #ifdef CURSOR_SHAPE
  379. State = NORMAL_BUSY;
  380. #endif
  381. #ifdef HAVE_LANGMAP
  382. /* adjust chars > 127, except after tTfFr command */
  383. LANGMAP_ADJUST(ca.nchar,
  384.    vim_strchr((char_u *)"tTfFr", ca.cmdchar) == NULL);
  385. #endif
  386. #ifdef RIGHTLEFT
  387. /* adjust Hebrew mapped char */
  388. if (p_hkmap && vim_strchr((char_u *)"tTfFr", ca.cmdchar) && KeyTyped)
  389.     ca.nchar = hkmap(ca.nchar);
  390. # ifdef FKMAP
  391. /* adjust Farsi mapped char */
  392. if (p_fkmap && strchr("tTfFr", ca.cmdchar) && KeyTyped)
  393.     ca.nchar = fkmap(ca.nchar);
  394. # endif
  395. #endif
  396. --no_mapping;
  397. --allow_keys;
  398. #ifdef SHOWCMD
  399. need_flushbuf |= add_to_showcmd(ca.nchar);
  400. #endif
  401.     }
  402. #ifdef SHOWCMD
  403.     /*
  404.      * Flush the showcmd characters onto the screen so we can see them while
  405.      * the command is being executed.  Only do this when the shown command was
  406.      * actually displayed, otherwise this will slow down a lot when executing
  407.      * mappings.
  408.      */
  409.     if (need_flushbuf)
  410. out_flush();
  411. #endif
  412.     State = NORMAL;
  413.     if (ca.nchar == ESC)
  414.     {
  415. clearop(oap);
  416. if (p_im && !restart_edit)
  417.     restart_edit = 'a';
  418. goto normal_end;
  419.     }
  420. #ifdef RIGHTLEFT
  421.     if (curwin->w_p_rl && KeyTyped) /* invert horizontal operations */
  422. switch (ca.cmdchar)
  423. {
  424.     case 'l':     ca.cmdchar = 'h'; break;
  425.     case K_RIGHT:   ca.cmdchar = K_LEFT; break;
  426.     case K_S_RIGHT: ca.cmdchar = K_S_LEFT; break;
  427.     case 'h':     ca.cmdchar = 'l'; break;
  428.     case K_LEFT:    ca.cmdchar = K_RIGHT; break;
  429.     case K_S_LEFT:  ca.cmdchar = K_S_RIGHT; break;
  430.     case '>':     ca.cmdchar = '<'; break;
  431.     case '<':     ca.cmdchar = '>'; break;
  432. }
  433. #endif
  434.     /* when 'keymode' contains "startsel" some keys start Select/Visual mode */
  435.     if (!VIsual_active && vim_strchr(p_km, 'a') != NULL)
  436.     {
  437. static int seltab[] =
  438. {
  439.     /* key unshifted shift included */
  440.     K_S_RIGHT, K_RIGHT, TRUE,
  441.     K_S_LEFT, K_LEFT, TRUE,
  442.     K_S_UP, K_UP, TRUE,
  443.     K_S_DOWN, K_DOWN, TRUE,
  444.     K_S_HOME, K_HOME, TRUE,
  445.     K_S_END, K_END, TRUE,
  446.     K_KHOME, K_KHOME, FALSE,
  447.     K_KEND, K_KEND, FALSE,
  448.     K_PAGEUP, K_PAGEUP, FALSE,
  449.     K_KPAGEUP, K_KPAGEUP, FALSE,
  450.     K_PAGEDOWN, K_PAGEDOWN, FALSE,
  451.     K_KPAGEDOWN, K_KPAGEDOWN, FALSE,
  452. };
  453. int i;
  454. for (i = 0; i < sizeof(seltab) / sizeof(int); i += 3)
  455. {
  456.     if (seltab[i] == ca.cmdchar
  457.     && (seltab[i + 2] || (mod_mask & MOD_MASK_SHIFT)))
  458.     {
  459. ca.cmdchar = seltab[i + 1];
  460. start_selection();
  461. break;
  462.     }
  463. }
  464.     }
  465.     msg_didout = FALSE;     /* don't scroll screen up for normal command */
  466.     msg_col = 0;
  467.     old_pos = curwin->w_cursor; /* remember where cursor was */
  468. /*
  469.  * Generally speaking, every command below should either clear any pending
  470.  * operator (with *clearop*()), or set the motion type variable
  471.  * oap->motion_type.
  472.  *
  473.  * When a cursor motion command is made, it is marked as being a character or
  474.  * line oriented motion.  Then, if an operator is in effect, the operation
  475.  * becomes character or line oriented accordingly.
  476.  */
  477. /*
  478.  * Variables available here:
  479.  * ca.cmdchar command character
  480.  * ca.nchar extra command character
  481.  * ca.count0 count before command (0 if no count given)
  482.  * ca.count1 count before command (1 if no count given)
  483.  * oap Operator Arguments (same as ca.oap)
  484.  * flag is FALSE, use as you like.
  485.  * dir is FORWARD, use as you like.
  486.  */
  487.     switch (ca.cmdchar)
  488.     {
  489. /*
  490.  * 0: Macros
  491.  */
  492.     case 'q':
  493. if (oap->op_type == OP_FORMAT)
  494.     nv_operator(&ca); /* "gqq": format line */
  495. else if (!checkclearop(oap))
  496. {
  497.     /* (stop) recording into a named register */
  498.     /* command is ignored while executing a register */
  499.     if (!Exec_reg && do_record(ca.nchar) == FAIL)
  500. clearopbeep(oap);
  501. }
  502. break;
  503.     case '@': /* execute a named register */
  504. nv_at(&ca);
  505. break;
  506. /*
  507.  * 1: Screen positioning commands
  508.  */
  509.     case Ctrl('D'):
  510.     case Ctrl('U'):
  511. nv_halfpage(&ca);
  512. break;
  513.     case Ctrl('B'):
  514.     case K_S_UP:
  515.     case K_PAGEUP:
  516.     case K_KPAGEUP:
  517. dir = BACKWARD;
  518.     case Ctrl('F'):
  519.     case K_S_DOWN:
  520.     case K_PAGEDOWN:
  521.     case K_KPAGEDOWN:
  522. if (checkclearop(oap))
  523.     break;
  524. (void)onepage(dir, ca.count1);
  525. break;
  526.     case Ctrl('E'):
  527. flag = TRUE;
  528. /* FALLTHROUGH */
  529.     case Ctrl('Y'):
  530. nv_scroll_line(&ca, flag);
  531. break;
  532.     case 'z':
  533. if (!checkclearop(oap))
  534.     nv_zet(&ca);
  535. break;
  536. /*
  537.  * 2: Control commands
  538.  */
  539.     case ':':
  540.    nv_colon(&ca);
  541.    break;
  542.     case 'Q':
  543. /*
  544.  * Ignore 'Q' in Visual mode, just give a beep.
  545.  */
  546. if (VIsual_active)
  547.     vim_beep();
  548. else if (!checkclearop(oap))
  549.     do_exmode();
  550. break;
  551.     case K_HELP:
  552.     case K_F1:
  553. if (!checkclearopq(oap))
  554.     do_help(NULL);
  555. break;
  556.     case Ctrl('L'):
  557. if (!checkclearop(oap))
  558. {
  559. #if defined(__BEOS__) && !USE_THREAD_FOR_INPUT_WITH_TIMEOUT
  560.     /*
  561.      * Right now, the BeBox doesn't seem to have an easy way to detect
  562.      * window resizing, so we cheat and make the user detect it
  563.      * manually with CTRL-L instead
  564.      */
  565.     ui_get_winsize();
  566. #endif
  567.     update_screen(CLEAR);
  568. }
  569. break;
  570.     case Ctrl('G'):
  571. nv_ctrlg(&ca);
  572. break;
  573.     case K_CCIRCM:     /* CTRL-^, short for ":e #" */
  574. if (!checkclearopq(oap))
  575.     (void)buflist_getfile((int)ca.count0, (linenr_t)0,
  576. GETF_SETMARK|GETF_ALT, FALSE);
  577. break;
  578.     case 'Z':
  579. nv_zzet(&ca);
  580. break;
  581.     case 163: /* the pound sign, '#' for English keyboards */
  582. ca.cmdchar = '#';
  583. /*FALLTHROUGH*/
  584.     case Ctrl(']'): /* :ta to current identifier */
  585.     case 'K': /* run program for current identifier */
  586.     case '*': /* / to current identifier or string */
  587.     case K_KMULTIPLY: /* same as '*' */
  588.     case '#': /* ? to current identifier or string */
  589. if (ca.cmdchar == K_KMULTIPLY)
  590.     ca.cmdchar = '*';
  591. nv_ident(&ca, &searchbuff);
  592. break;
  593.     case Ctrl('T'): /* backwards in tag stack */
  594. if (!checkclearopq(oap))
  595.     do_tag((char_u *)"", DT_POP, (int)ca.count1, FALSE, TRUE);
  596. break;
  597. /*
  598.  * Cursor motions
  599.  */
  600.     case 'G':
  601. nv_goto(oap, ca.count0 == 0 ? (long)curbuf->b_ml.ml_line_count
  602.     : ca.count0);
  603. break;
  604.     case 'H':
  605.     case 'M':
  606.     case 'L':
  607. nv_scroll(&ca);
  608. break;
  609.     case K_RIGHT:
  610. if (mod_mask & MOD_MASK_CTRL)
  611. {
  612.     oap->inclusive = FALSE;
  613.     nv_wordcmd(&ca, 1);
  614.     break;
  615. }
  616.     case 'l':
  617.     case ' ':
  618. nv_right(&ca);
  619. break;
  620.     case K_LEFT:
  621. if (mod_mask & MOD_MASK_CTRL)
  622. {
  623.     nv_bck_word(&ca, 1);
  624.     break;
  625. }
  626.     case 'h':
  627. dont_adjust_op_end = nv_left(&ca);
  628. break;
  629.     case K_BS:
  630.     case Ctrl('H'):
  631. if (VIsual_active && VIsual_select)
  632. {
  633.     ca.cmdchar = 'x'; /* BS key behaves like 'x' in Select mode */
  634.     v_visop(&ca);
  635. }
  636. else
  637.     dont_adjust_op_end = nv_left(&ca);
  638. break;
  639.     case '-':
  640.     case K_KMINUS:
  641. flag = TRUE;
  642. /* FALLTHROUGH */
  643.     case 'k':
  644.     case K_UP:
  645.     case Ctrl('P'):
  646. oap->motion_type = MLINE;
  647. if (cursor_up(ca.count1, oap->op_type == OP_NOP) == FAIL)
  648.     clearopbeep(oap);
  649. else if (flag)
  650.     beginline(BL_WHITE | BL_FIX);
  651. break;
  652.     case '+':
  653.     case K_KPLUS:
  654.     case CR:
  655.     case K_KENTER:
  656. flag = TRUE;
  657. /* FALLTHROUGH */
  658.     case 'j':
  659.     case K_DOWN:
  660.     case Ctrl('N'):
  661.     case NL:
  662. oap->motion_type = MLINE;
  663. if (cursor_down(ca.count1, oap->op_type == OP_NOP) == FAIL)
  664.     clearopbeep(oap);
  665. else if (flag)
  666.     beginline(BL_WHITE | BL_FIX);
  667. break;
  668. /*
  669.  * This is a strange motion command that helps make operators more
  670.  * logical. It is actually implemented, but not documented in the
  671.  * real Vi. This motion command actually refers to "the current
  672.  * line". Commands like "dd" and "yy" are really an alternate form of
  673.  * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  674.  * lines.
  675.  */
  676.     case '_':
  677. nv_lineop(&ca);
  678. break;
  679.     case K_HOME:
  680.     case K_KHOME:
  681.     case K_S_HOME:
  682. if ((mod_mask & MOD_MASK_CTRL))     /* CTRL-HOME = goto line 1 */
  683. {
  684.     nv_goto(oap, 1L);
  685.     break;
  686. }
  687. ca.count0 = 1;
  688. /* FALLTHROUGH */
  689.     case '|':
  690. nv_pipe(&ca);
  691. break;
  692.     /*
  693.      * Word Motions
  694.      */
  695.     case 'B':
  696. type = 1;
  697. /* FALLTHROUGH */
  698.     case 'b':
  699.     case K_S_LEFT:
  700. nv_bck_word(&ca, type);
  701. break;
  702.     case 'E':
  703. type = TRUE;
  704. /* FALLTHROUGH */
  705.     case 'e':
  706. oap->inclusive = TRUE;
  707. nv_wordcmd(&ca, type);
  708. break;
  709.     case 'W':
  710. type = TRUE;
  711. /* FALLTHROUGH */
  712.     case 'w':
  713.     case K_S_RIGHT:
  714. oap->inclusive = FALSE;
  715. nv_wordcmd(&ca, type);
  716. break;
  717.     case K_END:
  718.     case K_KEND:
  719.     case K_S_END:
  720. if ((mod_mask & MOD_MASK_CTRL))     /* CTRL-END = goto last line */
  721.     nv_goto(oap, curbuf->b_ml.ml_line_count);
  722. /* FALLTHROUGH */
  723.     case '$':
  724. oap->motion_type = MCHAR;
  725. oap->inclusive = TRUE;
  726. curwin->w_curswant = MAXCOL;     /* so we stay at the end */
  727. if (cursor_down((long)(ca.count1 - 1), oap->op_type == OP_NOP) == FAIL)
  728.     clearopbeep(oap);
  729. break;
  730.     case '^':
  731. flag = BL_WHITE | BL_FIX;
  732. /* FALLTHROUGH */
  733.     case '0':
  734. oap->motion_type = MCHAR;
  735. oap->inclusive = FALSE;
  736. beginline(flag);
  737. break;
  738. /*
  739.  * 4: Searches
  740.  */
  741.     case K_KDIVIDE:
  742. ca.cmdchar = '/';
  743. /* FALLTHROUGH */
  744.     case '?':
  745.     case '/':
  746. nv_search(&ca, &searchbuff, FALSE);
  747. break;
  748.     case 'N':
  749. flag = SEARCH_REV;
  750. /* FALLTHROUGH */
  751.     case 'n':
  752. nv_next(&ca, flag);
  753. break;
  754. /*
  755.  * Character searches
  756.  */
  757.     case 'T':
  758. dir = BACKWARD;
  759. /* FALLTHROUGH */
  760.     case 't':
  761. nv_csearch(&ca, dir, TRUE);
  762. break;
  763.     case 'F':
  764. dir = BACKWARD;
  765. /* FALLTHROUGH */
  766.     case 'f':
  767. nv_csearch(&ca, dir, FALSE);
  768. break;
  769.     case ',':
  770. flag = 1;
  771. /* FALLTHROUGH */
  772.     case ';':
  773. /* ca.nchar == NUL, thus repeat previous search */
  774. nv_csearch(&ca, flag, FALSE);
  775. break;
  776. /*
  777.  * section or C function searches
  778.  */
  779.     case '[':
  780. dir = BACKWARD;
  781. /* FALLTHROUGH */
  782.     case ']':
  783. nv_brackets(&ca, dir);
  784. break;
  785.     case '%':
  786. nv_percent(&ca);
  787. break;
  788.     case '(':
  789. dir = BACKWARD;
  790. /* FALLTHROUGH */
  791.     case ')':
  792. nv_brace(&ca, dir);
  793. break;
  794.     case '{':
  795. dir = BACKWARD;
  796. /* FALLTHROUGH */
  797.     case '}':
  798. oap->motion_type = MCHAR;
  799. oap->inclusive = FALSE;
  800. curwin->w_set_curswant = TRUE;
  801. if (!findpar(oap, dir, ca.count1, NUL, FALSE))
  802.     clearopbeep(oap);
  803. break;
  804. /*
  805.  * 5: Edits
  806.  */
  807.     case '.':     /* redo command */
  808. if (!checkclearopq(oap))
  809. {
  810.     /*
  811.      * if restart_edit is TRUE, the last but one command is repeated
  812.      * instead of the last command (inserting text). This is used for
  813.      * CTRL-O <.> in insert mode
  814.      */
  815.     if (start_redo(ca.count0, restart_edit && !arrow_used) == FAIL)
  816. clearopbeep(oap);
  817. }
  818. break;
  819.     case 'u':     /* undo */
  820. if (VIsual_active || oap->op_type == OP_LOWER)
  821. {
  822.     nv_operator(&ca);
  823.     break;
  824. }
  825. /* FALLTHROUGH */
  826.     case K_UNDO:
  827. if (!checkclearopq(oap))
  828. {
  829.     u_undo((int)ca.count1);
  830.     curwin->w_set_curswant = TRUE;
  831. }
  832. break;
  833.     case Ctrl('R'): /* undo undo */
  834. if (!checkclearopq(oap))
  835. {
  836.     u_redo((int)ca.count1);
  837.     curwin->w_set_curswant = TRUE;
  838. }
  839. break;
  840.     case 'U':     /* Undo line */
  841. nv_Undo(&ca);
  842. break;
  843.     case 'r':
  844. if (VIsual_active)
  845. {
  846.     ca.cmdchar = 'c';
  847.     nv_operator(&ca);
  848.     break;
  849. }
  850. if (!checkclearop(oap))
  851.     command_busy = n_replace(&ca);
  852. break;
  853.     case 'J':
  854. ca.oap->op_prechar = NUL; /* Thus not 'g', as in "gJ" */
  855. nv_join(&ca);
  856. break;
  857.     case 'P':
  858.     case 'p':
  859. nv_put(&ca);
  860. break;
  861.     case Ctrl('A'):     /* add to number */
  862.     case Ctrl('X'):     /* subtract from number */
  863. if (!checkclearopq(oap) && do_addsub((int)ca.cmdchar, ca.count1) == OK)
  864.     prep_redo_cmd(&ca);
  865. break;
  866. /*
  867.  * 6: Inserts
  868.  */
  869.     case 'A':
  870. if (checkclearopq(oap))
  871.     break;
  872. /* FALLTHROUGH */
  873.     case 'a':
  874. command_busy = nv_append(&ca);
  875. break;
  876.     case 'I':
  877. if (checkclearopq(oap))
  878.     break;
  879. beginline(BL_WHITE);
  880. /* FALLTHROUGH */
  881.     case 'i':
  882. if (ca.cmdchar == 'i' && (oap->op_type != OP_NOP || VIsual_active))
  883. {
  884. #ifdef TEXT_OBJECTS
  885.     nv_object(&ca); /* 'i'nner text object */
  886. #else
  887.     clearopbeep(oap);
  888. #endif
  889.     break;
  890. }
  891. /* FALLTHROUGH */
  892.     case K_INS:
  893. if (!checkclearopq(oap))
  894. {
  895.     if (u_save_cursor() == OK)
  896. command_busy = edit(ca.cmdchar, FALSE, ca.count1);
  897. }
  898. break;
  899.     case 'o':
  900.     case 'O':
  901. if (VIsual_active)  /* switch start and end of visual */
  902.     v_swap_corners(&ca);
  903. else
  904.     command_busy = n_opencmd(&ca);
  905. break;
  906.     case 'R':
  907. command_busy = nv_replace(&ca);
  908. break;
  909. /*
  910.  * 7: Operators
  911.  */
  912.     case '~':     /* swap case */
  913. /*
  914.  * if tilde is not an operator and Visual is off: swap case
  915.  * of a single character
  916.  */
  917. if (    !p_to
  918. && !VIsual_active
  919. && oap->op_type != OP_TILDE)
  920. {
  921.     n_swapchar(&ca);
  922.     break;
  923. }
  924. /*FALLTHROUGH*/
  925.     case 'd':
  926.     case 'c':
  927.     case 'y':
  928.     case '>':
  929.     case '<':
  930.     case '!':
  931.     case '=':
  932. nv_operator(&ca);
  933. break;
  934. /*
  935.  * 8: Abbreviations
  936.  */
  937.     case 'S':
  938.     case 's':
  939. if (VIsual_active) /* "vs" and "vS" are the same as "vc" */
  940. {
  941.     if (ca.cmdchar == 'S')
  942. VIsual_mode = 'V';
  943.     ca.cmdchar = 'c';
  944.     nv_operator(&ca);
  945.     break;
  946. }
  947. /* FALLTHROUGH */
  948.     case K_DEL:
  949.     case 'Y':
  950.     case 'D':
  951.     case 'C':
  952.     case 'x':
  953.     case 'X':
  954. if (ca.cmdchar == K_DEL)
  955.     ca.cmdchar = 'x'; /* DEL key behaves like 'x' */
  956. /* with Visual these commands are operators */
  957. if (VIsual_active)
  958. {
  959.     v_visop(&ca);
  960.     break;
  961. }
  962. /* FALLTHROUGH */
  963.     case '&':
  964. nv_optrans(&ca);
  965. opnum = 0;
  966. break;
  967. /*
  968.  * 9: Marks
  969.  */
  970.     case 'm':
  971. if (!checkclearop(oap))
  972. {
  973.     if (setmark(ca.nchar) == FAIL)
  974. clearopbeep(oap);
  975. }
  976. break;
  977.     case ''':
  978. flag = TRUE;
  979. /* FALLTHROUGH */
  980.     case '`':
  981. nv_gomark(&ca, flag);
  982. break;
  983.     case Ctrl('O'):
  984. /* switch from Select to Visual mode for one command */
  985. if (VIsual_active && VIsual_select)
  986. {
  987.     VIsual_select = FALSE;
  988.     showmode();
  989.     restart_VIsual_select = 2;
  990.     break;
  991. }
  992. ca.count1 = -ca.count1; /* goto older pcmark */
  993. /* FALLTHROUGH */
  994.     case Ctrl('I'): /* goto newer pcmark */
  995. nv_pcmark(&ca);
  996. break;
  997. /*
  998.  * 10. Register name setting
  999.  */
  1000.     case '"':
  1001. nv_regname(&ca, &opnum);
  1002. break;
  1003. /*
  1004.  * 11. Visual
  1005.  */
  1006.     case 'v':
  1007.     case 'V':
  1008.     case Ctrl('V'):
  1009. if (!checkclearop(oap))
  1010.     nv_visual(&ca, FALSE);
  1011. break;
  1012. /*
  1013.  * 12. Suspend
  1014.  */
  1015.     case Ctrl('Z'):
  1016. clearop(oap);
  1017. if (VIsual_active)
  1018.     end_visual_mode();     /* stop Visual */
  1019. stuffReadbuff((char_u *)":str");   /* with autowrite */
  1020. break;
  1021. /*
  1022.  * 13. Window commands
  1023.  */
  1024.     case Ctrl('W'):
  1025. if (!checkclearop(oap))
  1026.     do_window(ca.nchar, ca.count0); /* everything is in window.c */
  1027. break;
  1028. /*
  1029.  *   14. extended commands (starting with 'g')
  1030.  */
  1031.     case 'g':
  1032. command_busy = nv_g_cmd(&ca, &searchbuff);
  1033. break;
  1034. /*
  1035.  * 15. mouse click
  1036.  */
  1037. #ifdef USE_MOUSE
  1038.     case K_MIDDLEMOUSE:
  1039.     case K_MIDDLEDRAG:
  1040.     case K_MIDDLERELEASE:
  1041.     case K_LEFTMOUSE:
  1042.     case K_LEFTDRAG:
  1043.     case K_LEFTRELEASE:
  1044.     case K_RIGHTMOUSE:
  1045.     case K_RIGHTDRAG:
  1046.     case K_RIGHTRELEASE:
  1047. (void)do_mouse(oap, ca.cmdchar, BACKWARD, ca.count1, 0);
  1048. break;
  1049.     case K_IGNORE:
  1050. break;
  1051. #endif
  1052. #ifdef USE_GUI
  1053. /*
  1054.  * 16. scrollbar movement
  1055.  */
  1056.     case K_SCROLLBAR:
  1057. if (oap->op_type != OP_NOP)
  1058.     clearopbeep(oap);
  1059. /* Even if an operator was pending, we still want to scroll */
  1060. gui_do_scroll();
  1061. break;
  1062.     case K_HORIZ_SCROLLBAR:
  1063. if (oap->op_type != OP_NOP)
  1064.     clearopbeep(oap);
  1065. /* Even if an operator was pending, we still want to scroll */
  1066. gui_do_horiz_scroll();
  1067. break;
  1068. #endif
  1069.     case K_SELECT:     /* end of Select mode mapping */
  1070. nv_select(&ca);
  1071. break;
  1072. #ifdef FKMAP
  1073.       case K_F8:
  1074.       case K_F9:
  1075. farsi_fkey(ca.cmdchar);
  1076. break;
  1077. #endif
  1078. #ifdef USE_SNIFF
  1079.       case K_SNIFF:
  1080. ProcessSniffRequests();
  1081. break;
  1082. #endif
  1083. /*
  1084.  * 17. The end
  1085.  */
  1086.     case Ctrl('C'):
  1087. restart_edit = 0;
  1088. /*FALLTHROUGH*/
  1089.     case ESC:
  1090. nv_esc(&ca, opnum);
  1091. break;
  1092.     default: /* not a known command */
  1093. clearopbeep(oap);
  1094. break;
  1095.     } /* end of switch on command character */
  1096. /*
  1097.  * if we didn't start or finish an operator, reset oap->regname, unless we
  1098.  * need it later.
  1099.  */
  1100.     if (!finish_op && !oap->op_type &&
  1101.        vim_strchr((char_u *)""DCYSsXx.", ca.cmdchar) == NULL)
  1102. oap->regname = 0;
  1103. /*
  1104.  * If an operation is pending, handle it...
  1105.  */
  1106.     do_pending_operator(&ca, searchbuff,
  1107.    &command_busy, old_col, FALSE, dont_adjust_op_end);
  1108.     /*
  1109.      * Wait when a message is displayed that will be overwritten by the mode
  1110.      * message.
  1111.      * In Visual mode and with "^O" in Insert mode, a short message will be
  1112.      * overwritten by the mode message.  Wait a bit, until a key is hit.
  1113.      * In Visual mode, it's more important to keep the Visual area updated
  1114.      * than keeping a message (e.g. from a /pat search).
  1115.      * Only do this if the command was typed, not from a mapping.
  1116.      * Also wait a bit after an error message, e.g. for "^O:".
  1117.      * Don't redraw the screen, it would remove the message.
  1118.      */
  1119.     if (       ((p_smd
  1120.     && ((VIsual_active
  1121.     && old_pos.lnum == curwin->w_cursor.lnum
  1122.     && old_pos.col == curwin->w_cursor.col)
  1123. || restart_edit)
  1124.     && (clear_cmdline
  1125. || redraw_cmdline)
  1126.     && msg_didany
  1127.     && !msg_nowait
  1128.     && KeyTyped)
  1129. || (restart_edit
  1130.     && !VIsual_active
  1131.     && (msg_scroll
  1132. || emsg_on_display)))
  1133.     && oap->regname == 0
  1134.     && !command_busy
  1135.     && stuff_empty()
  1136.     && typebuf_typed()
  1137.     && oap->op_type == OP_NOP)
  1138.     {
  1139. /* If need to redraw, and there is a "keep_msg", redraw before the
  1140.  * delay */
  1141. if (must_redraw && keep_msg != NULL && !emsg_on_display)
  1142. {
  1143.     char_u *kmsg = keep_msg;
  1144.     /* showmode() will clear keep_msg, but we want to use it anyway */
  1145.     update_screen(must_redraw);
  1146.     msg_attr(kmsg, keep_msg_attr);
  1147. }
  1148. setcursor();
  1149. cursor_on();
  1150. out_flush();
  1151. if (msg_scroll || emsg_on_display)
  1152.     ui_delay(1000L, TRUE); /* wait at least one second */
  1153. ui_delay(3000L, FALSE); /* wait up to three seconds */
  1154. msg_scroll = FALSE;
  1155. emsg_on_display = FALSE;
  1156.     }
  1157.     /*
  1158.      * Finish up after executing a Normal mode command.
  1159.      */
  1160. normal_end:
  1161.     msg_nowait = FALSE;
  1162.     /* Reset finish_op, in case it was set */
  1163. #ifdef USE_GUI
  1164.     c = finish_op;
  1165. #endif
  1166.     finish_op = FALSE;
  1167. #ifdef CURSOR_SHAPE
  1168.     /* Redraw the cursor with another shape, if we were in Operator-pending
  1169.      * mode or did a replace command. */
  1170.     if ((c && !finish_op) || ca.cmdchar == 'r')
  1171. ui_cursor_shape(); /* may show different cursor shape */
  1172. #endif
  1173. #ifdef SHOWCMD
  1174.     if (oap->op_type == OP_NOP && oap->regname == 0)
  1175. clear_showcmd();
  1176. #endif
  1177.     /*
  1178.      * Update the other windows for the current buffer if modified has been
  1179.      * set in set_Changed() (This should be done more efficiently)
  1180.      */
  1181.     if (modified)
  1182.     {
  1183. update_other_win();
  1184. modified = FALSE;
  1185.     }
  1186.     checkpcmark(); /* check if we moved since setting pcmark */
  1187.     vim_free(searchbuff);
  1188.     /*
  1189.      * May restart edit(), if we got here with CTRL-O in Insert mode (but not
  1190.      * if still inside a mapping that started in Visual mode).
  1191.      * May switch from Visual to Select mode after CTRL-O command.
  1192.      */
  1193.     if (      ((restart_edit && !VIsual_active && old_mapped_len == 0)
  1194. || restart_VIsual_select == 1)
  1195.     && oap->op_type == OP_NOP
  1196.     && !command_busy
  1197.     && stuff_empty()
  1198.     && oap->regname == 0)
  1199.     {
  1200. if (restart_VIsual_select == 1)
  1201. {
  1202.     VIsual_select = TRUE;
  1203.     showmode();
  1204.     restart_VIsual_select = 0;
  1205. }
  1206. if (restart_edit && !VIsual_active && old_mapped_len == 0)
  1207.     (void)edit(restart_edit, FALSE, 1L);
  1208.     }
  1209.     if (restart_VIsual_select == 2)
  1210. restart_VIsual_select = 1;
  1211. #ifdef MULTI_BYTE
  1212.     if (is_dbcs)
  1213. AdjustCursorForMultiByteCharacter();
  1214. #endif
  1215. }
  1216. /*
  1217.  * Handle an operator after visual mode or when the movement is finished
  1218.  */
  1219.     void
  1220. do_pending_operator(cap, searchbuff,
  1221.   command_busy, old_col, gui_yank, dont_adjust_op_end)
  1222.     CMDARG *cap;
  1223.     char_u *searchbuff;
  1224.     int *command_busy;
  1225.     int old_col;
  1226.     int gui_yank;     /* yanking visual area for GUI */
  1227.     int dont_adjust_op_end;
  1228. {
  1229.     OPARG *oap = cap->oap;
  1230.     FPOS old_cursor;
  1231.     int empty_region_error;
  1232.     /* The visual area is remembered for redo */
  1233.     static int     redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
  1234.     static linenr_t redo_VIsual_line_count; /* number of lines */
  1235.     static colnr_t  redo_VIsual_col;     /* number of cols or end column */
  1236.     static long     redo_VIsual_count;     /* count for Visual operator */
  1237. #if defined(USE_CLIPBOARD) && !defined(WIN32)
  1238.     /*
  1239.      * Yank the visual area into the GUI selection register before we operate
  1240.      * on it and lose it forever.  This could call do_pending_operator()
  1241.      * recursively, but that's OK because gui_yank will be TRUE for the
  1242.      * nested call.  Note also that we call clip_copy_selection() and not
  1243.      * clip_auto_select().  This is because even when 'autoselect' is not set,
  1244.      * if we operate on the text, eg by deleting it, then this is considered to
  1245.      * be an explicit request for it to be put in the global cut buffer, so we
  1246.      * always want to do it here. -- webb
  1247.      */
  1248.     /* WIN32: don't do this, there is no automatic copy to the clipboard */
  1249.     /* Don't do it if a specific register was specified, so that ""x"*P works */
  1250.     if (clipboard.available
  1251.     && oap->op_type != OP_NOP
  1252.     && !gui_yank
  1253.     && VIsual_active
  1254.     && oap->regname == 0
  1255.     && !redo_VIsual_busy)
  1256. clip_copy_selection();
  1257. #endif
  1258.     old_cursor = curwin->w_cursor;
  1259.     /*
  1260.      * If an operation is pending, handle it...
  1261.      */
  1262.     if ((VIsual_active || finish_op) && oap->op_type != OP_NOP)
  1263.     {
  1264. oap->is_VIsual = VIsual_active;
  1265. /* only redo yank when 'y' flag is in 'cpoptions' */
  1266. if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
  1267. && !VIsual_active)
  1268. {
  1269.     prep_redo(oap->regname, cap->count0, oap->op_prechar,
  1270. op_chars[oap->op_type - 1], cap->cmdchar, cap->nchar);
  1271.     if (cap->cmdchar == '/' || cap->cmdchar == '?') /* was a search */
  1272.     {
  1273. /*
  1274.  * If 'cpoptions' does not contain 'r', insert the search
  1275.  * pattern to really repeat the same command.
  1276.  */
  1277. if (vim_strchr(p_cpo, CPO_REDO) == NULL)
  1278.     AppendToRedobuff(searchbuff);
  1279. AppendToRedobuff(NL_STR);
  1280.     }
  1281. }
  1282. if (redo_VIsual_busy)
  1283. {
  1284.     oap->start = curwin->w_cursor;
  1285.     curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
  1286.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1287. curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1288.     VIsual_mode = redo_VIsual_mode;
  1289.     if (VIsual_mode == 'v')
  1290.     {
  1291. if (redo_VIsual_line_count <= 1)
  1292.     curwin->w_cursor.col += redo_VIsual_col - 1;
  1293. else
  1294.     curwin->w_cursor.col = redo_VIsual_col;
  1295.     }
  1296.     if (redo_VIsual_col == MAXCOL)
  1297.     {
  1298. curwin->w_curswant = MAXCOL;
  1299. coladvance(MAXCOL);
  1300.     }
  1301.     cap->count0 = redo_VIsual_count;
  1302.     if (redo_VIsual_count != 0)
  1303. cap->count1 = redo_VIsual_count;
  1304.     else
  1305. cap->count1 = 1;
  1306. }
  1307. else if (VIsual_active)
  1308. {
  1309.     /* In Select mode, a linewise selection is operated upon like a
  1310.      * characterwise selection. */
  1311.     if (VIsual_select && VIsual_mode == 'V')
  1312.     {
  1313. if (lt(VIsual, curwin->w_cursor))
  1314. {
  1315.     VIsual.col = 0;
  1316.     curwin->w_cursor.col =
  1317. STRLEN(ml_get(curwin->w_cursor.lnum));
  1318. }
  1319. else
  1320. {
  1321.     curwin->w_cursor.col = 0;
  1322.     VIsual.col = STRLEN(ml_get(VIsual.lnum));
  1323. }
  1324. VIsual_mode = 'v';
  1325.     }
  1326.     /* If 'selection' is "exclusive", backup one character for
  1327.      * charwise selections. */
  1328.     else if (*p_sel == 'e' && VIsual_mode == 'v'
  1329.   && !equal(VIsual, curwin->w_cursor))
  1330.     {
  1331. FPOS *pp;
  1332. if (lt(VIsual, curwin->w_cursor))
  1333.     pp = &curwin->w_cursor;
  1334. else
  1335.     pp = &VIsual;
  1336. if (pp->col > 0)
  1337.     --pp->col;
  1338. else if (pp->lnum > 1)
  1339. {
  1340.     --pp->lnum;
  1341.     pp->col = STRLEN(ml_get(pp->lnum));
  1342. }
  1343.     }
  1344.     /* Save the current VIsual area for '< and '> marks, and "gv" */
  1345.     curbuf->b_visual_start = VIsual;
  1346.     curbuf->b_visual_end = curwin->w_cursor;
  1347.     curbuf->b_visual_mode = VIsual_mode;
  1348.     oap->start = VIsual;
  1349.     if (VIsual_mode == 'V')
  1350. oap->start.col = 0;
  1351. }
  1352. /*
  1353.  * Set oap->start to the first position of the operated text, oap->end
  1354.  * to the end of the operated text.  w_cursor is equal to oap->start.
  1355.  */
  1356. if (lt(oap->start, curwin->w_cursor))
  1357. {
  1358.     oap->end = curwin->w_cursor;
  1359.     curwin->w_cursor = oap->start;
  1360. }
  1361. else
  1362. {
  1363.     oap->end = oap->start;
  1364.     oap->start = curwin->w_cursor;
  1365. }
  1366. #ifdef MULTI_BYTE
  1367. if (is_dbcs && (VIsual_active || oap->inclusive))
  1368. {
  1369.     char_u *p;
  1370.     p = ml_get(oap->end.lnum);
  1371.     if (IsTrailByte(p, p + oap->end.col + 1))
  1372. oap->end.col++;
  1373. }
  1374. #endif
  1375. oap->line_count = oap->end.lnum - oap->start.lnum + 1;
  1376. if (VIsual_active || redo_VIsual_busy)
  1377. {
  1378.     if (VIsual_mode == Ctrl('V')) /* block mode */
  1379.     {
  1380. colnr_t     start, end;
  1381. oap->block_mode = TRUE;
  1382. getvcol(curwin, &(oap->start),
  1383.       &oap->start_vcol, NULL, &oap->end_vcol);
  1384. if (!redo_VIsual_busy)
  1385. {
  1386.     getvcol(curwin, &(oap->end), &start, NULL, &end);
  1387.     if (start < oap->start_vcol)
  1388. oap->start_vcol = start;
  1389.     if (end > oap->end_vcol)
  1390.     {
  1391. if (*p_sel == 'e' && start - 1 >= oap->end_vcol)
  1392.     oap->end_vcol = start - 1;
  1393. else
  1394.     oap->end_vcol = end;
  1395.     }
  1396. }
  1397. /* if '$' was used, get oap->end_vcol from longest line */
  1398. if (curwin->w_curswant == MAXCOL)
  1399. {
  1400.     curwin->w_cursor.col = MAXCOL;
  1401.     oap->end_vcol = 0;
  1402.     for (curwin->w_cursor.lnum = oap->start.lnum;
  1403.     curwin->w_cursor.lnum <= oap->end.lnum;
  1404.       ++curwin->w_cursor.lnum)
  1405.     {
  1406. getvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
  1407. if (end > oap->end_vcol)
  1408.     oap->end_vcol = end;
  1409.     }
  1410. }
  1411. else if (redo_VIsual_busy)
  1412.     oap->end_vcol = oap->start_vcol + redo_VIsual_col - 1;
  1413. /*
  1414.  * Correct oap->end.col and oap->start.col to be the
  1415.  * upper-left and lower-right corner of the block area.
  1416.  */
  1417. curwin->w_cursor.lnum = oap->end.lnum;
  1418. coladvance(oap->end_vcol);
  1419. oap->end = curwin->w_cursor;
  1420. curwin->w_cursor = oap->start;
  1421. coladvance(oap->start_vcol);
  1422. oap->start = curwin->w_cursor;
  1423.     }
  1424.     if (!redo_VIsual_busy && !gui_yank)
  1425.     {
  1426. /*
  1427.  * Prepare to reselect and redo Visual: this is based on the
  1428.  * size of the Visual text
  1429.  */
  1430. resel_VIsual_mode = VIsual_mode;
  1431. if (curwin->w_curswant == MAXCOL)
  1432.     resel_VIsual_col = MAXCOL;
  1433. else if (VIsual_mode == Ctrl('V'))
  1434.     resel_VIsual_col = oap->end_vcol - oap->start_vcol + 1;
  1435. else if (oap->line_count > 1)
  1436.     resel_VIsual_col = oap->end.col;
  1437. else
  1438.     resel_VIsual_col = oap->end.col - oap->start.col + 1;
  1439. resel_VIsual_line_count = oap->line_count;
  1440.     }
  1441.     /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
  1442.     if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
  1443.     && oap->op_type != OP_COLON)
  1444.     {
  1445. prep_redo(oap->regname, 0L, NUL, 'v', oap->op_prechar,
  1446.   op_chars[oap->op_type - 1]);
  1447. redo_VIsual_mode = resel_VIsual_mode;
  1448. redo_VIsual_col = resel_VIsual_col;
  1449. redo_VIsual_line_count = resel_VIsual_line_count;
  1450. redo_VIsual_count = cap->count0;
  1451.     }
  1452.     /*
  1453.      * oap->inclusive defaults to TRUE.
  1454.      * If oap->end is on a NUL (empty line) oap->inclusive becomes
  1455.      * FALSE.  This makes "d}P" and "v}dP" work the same.
  1456.      */
  1457.     oap->inclusive = TRUE;
  1458.     if (VIsual_mode == 'V')
  1459. oap->motion_type = MLINE;
  1460.     else
  1461.     {
  1462. oap->motion_type = MCHAR;
  1463. if (VIsual_mode != Ctrl('V') && *ml_get_pos(&(oap->end)) == NUL)
  1464. {
  1465.     oap->inclusive = FALSE;
  1466.     /* Try to include the newline */
  1467.     if (*p_sel != 'o'
  1468.     && oap->end.lnum < curbuf->b_ml.ml_line_count)
  1469.     {
  1470. ++oap->end.lnum;
  1471. oap->end.col = 0;
  1472. ++oap->line_count;
  1473.     }
  1474. }
  1475.     }
  1476.     redo_VIsual_busy = FALSE;
  1477.     /*
  1478.      * Switch Visual off now, so screen updating does
  1479.      * not show inverted text when the screen is redrawn.
  1480.      * With OP_YANK and sometimes with OP_COLON and OP_FILTER there is
  1481.      * no screen redraw, so it is done here to remove the inverted
  1482.      * part.
  1483.      */
  1484.     if (!gui_yank)
  1485.     {
  1486. VIsual_active = FALSE;
  1487. #ifdef USE_MOUSE
  1488. setmouse();
  1489. #endif
  1490. if (p_smd)
  1491.     clear_cmdline = TRUE;   /* unshow visual mode later */
  1492. if (oap->op_type == OP_YANK || oap->op_type == OP_COLON ||
  1493.      oap->op_type == OP_FILTER)
  1494.     update_curbuf(NOT_VALID);
  1495.     }
  1496. }
  1497. curwin->w_set_curswant = TRUE;
  1498. /*
  1499.  * oap->empty is set when start and end are the same.  The inclusive
  1500.  * flag affects this too, unless yanking and the end is on a NUL.
  1501.  */
  1502. oap->empty = (oap->motion_type == MCHAR
  1503.     && (!oap->inclusive
  1504. || (oap->op_type == OP_YANK && gchar(&oap->end) == NUL))
  1505.     && equal(oap->start, oap->end));
  1506. /*
  1507.  * For delete, change and yank, it's an error to operate on an
  1508.  * empty region, when 'E' inclucded in 'cpoptions' (Vi compatible).
  1509.  */
  1510. empty_region_error = (oap->empty
  1511. && vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL);
  1512. /* Force a redraw when operating on an empty Visual region */
  1513. if (oap->is_VIsual && oap->empty)
  1514.     redraw_curbuf_later(NOT_VALID);
  1515.     /*
  1516.      * If the end of an operator is in column one while oap->motion_type is
  1517.      * MCHAR and oap->inclusive is FALSE, we put op_end after the last character
  1518.      * in the previous line. If op_start is on or before the first non-blank
  1519.      * in the line, the operator becomes linewise (strange, but that's the way
  1520.      * vi does it).
  1521.      */
  1522. if (    oap->motion_type == MCHAR
  1523. && oap->inclusive == FALSE
  1524. && !dont_adjust_op_end
  1525. && oap->end.col == 0
  1526. && (!oap->is_VIsual || *p_sel == 'o')
  1527. && oap->line_count > 1)
  1528. {
  1529.     oap->end_adjusted = TRUE;     /* remember that we did this */
  1530.     --oap->line_count;
  1531.     --oap->end.lnum;
  1532.     if (inindent(0))
  1533. oap->motion_type = MLINE;
  1534.     else
  1535.     {
  1536. oap->end.col = STRLEN(ml_get(oap->end.lnum));
  1537. if (oap->end.col)
  1538. {
  1539.     --oap->end.col;
  1540.     oap->inclusive = TRUE;
  1541. }
  1542.     }
  1543. }
  1544. else
  1545.     oap->end_adjusted = FALSE;
  1546. switch (oap->op_type)
  1547. {
  1548. case OP_LSHIFT:
  1549. case OP_RSHIFT:
  1550.     op_shift(oap, TRUE, oap->is_VIsual ? (int)cap->count1 : 1);
  1551.     break;
  1552. case DO_JOIN:
  1553.     if (oap->line_count < 2)
  1554. oap->line_count = 2;
  1555.     if (curwin->w_cursor.lnum + oap->line_count - 1 >
  1556.    curbuf->b_ml.ml_line_count)
  1557. beep_flush();
  1558.     else
  1559. do_do_join(oap->line_count, !oap->op_prechar, TRUE);
  1560.     break;
  1561. case OP_DELETE:
  1562.     VIsual_reselect = FALSE;     /* don't reselect now */
  1563.     if (empty_region_error)
  1564. vim_beep();
  1565.     else
  1566. (void)op_delete(oap);
  1567.     break;
  1568. case OP_YANK:
  1569.     if (empty_region_error)
  1570.     {
  1571. if (!gui_yank)
  1572.     vim_beep();
  1573.     }
  1574.     else
  1575. (void)op_yank(oap, FALSE, !gui_yank);
  1576.     break;
  1577. case OP_CHANGE:
  1578.     VIsual_reselect = FALSE;     /* don't reselect now */
  1579.     if (empty_region_error)
  1580. vim_beep();
  1581.     else
  1582.     {
  1583. /* don't restart edit after typing <Esc> in edit() */
  1584. restart_edit = 0;
  1585. *command_busy = op_change(oap); /* will call edit() */
  1586.     }
  1587.     break;
  1588. case OP_FILTER:
  1589.     if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
  1590. AppendToRedobuff((char_u *)"!r");  /* use any last used !cmd */
  1591.     else
  1592. bangredo = TRUE;    /* do_bang() will put cmd in redo buffer */
  1593. case OP_INDENT:
  1594. case OP_COLON:
  1595. #if defined(LISPINDENT) || defined(CINDENT)
  1596.     /*
  1597.      * If 'equalprg' is empty, do the indenting internally.
  1598.      */
  1599.     if (oap->op_type == OP_INDENT && *p_ep == NUL)
  1600.     {
  1601. # ifdef LISPINDENT
  1602. if (curbuf->b_p_lisp)
  1603. {
  1604.     op_reindent(oap, get_lisp_indent);
  1605.     break;
  1606. }
  1607. # endif
  1608. # ifdef CINDENT
  1609. op_reindent(oap, get_c_indent);
  1610. break;
  1611. # endif
  1612.     }
  1613. #endif /* defined(LISPINDENT) || defined(CINDENT) */
  1614.     op_colon(oap);
  1615.     break;
  1616. case OP_TILDE:
  1617. case OP_UPPER:
  1618. case OP_LOWER:
  1619.     if (empty_region_error)
  1620. vim_beep();
  1621.     else
  1622. op_tilde(oap);
  1623.     break;
  1624. case OP_FORMAT:
  1625.     if (*p_fp != NUL)
  1626. op_colon(oap); /* use external command */
  1627.     else
  1628. op_format(oap); /* use internal function */
  1629.     break;
  1630. default:
  1631.     clearopbeep(oap);
  1632. }
  1633. oap->op_prechar = NUL;
  1634. if (!gui_yank)
  1635. {
  1636.     /*
  1637.      * if 'sol' not set, go back to old column for some commands
  1638.      */
  1639.     if (!p_sol && oap->motion_type == MLINE && !oap->end_adjusted
  1640.     && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT
  1641. || oap->op_type == OP_DELETE))
  1642. coladvance(curwin->w_curswant = old_col);
  1643.     oap->op_type = OP_NOP;
  1644. }
  1645. else
  1646.     curwin->w_cursor = old_cursor;
  1647. oap->block_mode = FALSE;
  1648. oap->regname = 0;
  1649.     }
  1650. }
  1651. /*
  1652.  * Handle indent and format operators and visual mode ":".
  1653.  */
  1654.     static void
  1655. op_colon(oap)
  1656.     OPARG *oap;
  1657. {
  1658.     stuffcharReadbuff(':');
  1659.     if (oap->is_VIsual)
  1660. stuffReadbuff((char_u *)"'<,'>");
  1661.     else
  1662.     {
  1663. /*
  1664.  * Make the range look nice, so it can be repeated.
  1665.  */
  1666. if (oap->start.lnum == curwin->w_cursor.lnum)
  1667.     stuffcharReadbuff('.');
  1668. else
  1669.     stuffnumReadbuff((long)oap->start.lnum);
  1670. if (oap->end.lnum != oap->start.lnum)
  1671. {
  1672.     stuffcharReadbuff(',');
  1673.     if (oap->end.lnum == curwin->w_cursor.lnum)
  1674. stuffcharReadbuff('.');
  1675.     else if (oap->end.lnum == curbuf->b_ml.ml_line_count)
  1676. stuffcharReadbuff('$');
  1677.     else if (oap->start.lnum == curwin->w_cursor.lnum)
  1678.     {
  1679. stuffReadbuff((char_u *)".+");
  1680. stuffnumReadbuff((long)oap->line_count - 1);
  1681.     }
  1682.     else
  1683. stuffnumReadbuff((long)oap->end.lnum);
  1684. }
  1685.     }
  1686.     if (oap->op_type != OP_COLON)
  1687. stuffReadbuff((char_u *)"!");
  1688.     if (oap->op_type == OP_INDENT)
  1689.     {
  1690. #ifndef CINDENT
  1691. if (*p_ep == NUL)
  1692.     stuffReadbuff((char_u *)"indent");
  1693. else
  1694. #endif
  1695.     stuffReadbuff(p_ep);
  1696. stuffReadbuff((char_u *)"n");
  1697.     }
  1698.     else if (oap->op_type == OP_FORMAT)
  1699.     {
  1700. if (*p_fp == NUL)
  1701.     stuffReadbuff((char_u *)"fmt");
  1702. else
  1703.     stuffReadbuff(p_fp);
  1704. stuffReadbuff((char_u *)"n");
  1705.     }
  1706.     /*
  1707.      * do_cmdline() does the rest
  1708.      */
  1709. }
  1710. #ifdef USE_MOUSE
  1711. /*
  1712.  * Do the appropriate action for the current mouse click in the current mode.
  1713.  *
  1714.  * Normal Mode:
  1715.  * event  modi- position      visual    change   action
  1716.  *  fier cursor    window
  1717.  * left press   - yes     end     yes
  1718.  * left press   C yes     end     yes     "^]" (2)
  1719.  * left press   S yes     end     yes     "*" (2)
  1720.  * left drag   - yes start if moved     no
  1721.  * left relse   - yes start if moved     no
  1722.  * middle press   - yes  if not active     no     put register
  1723.  * middle press   - yes  if active     no     yank and put
  1724.  * right press   - yes start or extend     yes
  1725.  * right press   S yes no change     yes     "#" (2)
  1726.  * right drag   - yes extend     no
  1727.  * right relse   - yes extend     no
  1728.  *
  1729.  * Insert or Replace Mode:
  1730.  * event  modi- position      visual    change   action
  1731.  *  fier cursor    window
  1732.  * left press   - yes (cannot be active)  yes
  1733.  * left press   C yes (cannot be active)  yes     "CTRL-O^]" (2)
  1734.  * left press   S yes (cannot be active)  yes     "CTRL-O*" (2)
  1735.  * left drag   - yes start or extend (1) no     CTRL-O (1)
  1736.  * left relse   - yes start or extend (1) no     CTRL-O (1)
  1737.  * middle press   - no (cannot be active)  no     put register
  1738.  * right press   - yes start or extend     yes     CTRL-O
  1739.  * right press   S yes (cannot be active)  yes     "CTRL-O#" (2)
  1740.  *
  1741.  * (1) only if mouse pointer moved since press
  1742.  * (2) only if click is in same buffer
  1743.  *
  1744.  * Return TRUE if start_arrow() should be called for edit mode.
  1745.  */
  1746.     int
  1747. do_mouse(oap, c, dir, count, fix_indent)
  1748.     OPARG   *oap;     /* operator argument, can be NULL */
  1749.     int     c;     /* K_LEFTMOUSE, etc */
  1750.     int     dir;     /* Direction to 'put' if necessary */
  1751.     long    count;
  1752.     int     fix_indent;     /* PUT_FIXINDENT if fixing indent necessary */
  1753. {
  1754.     static FPOS orig_cursor;
  1755.     static int do_always = FALSE; /* ignore 'mouse' setting next time */
  1756.     static int got_click = FALSE; /* got a click some time back */
  1757.     int     which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
  1758.     int     is_click; /* If FALSE it's a drag or release event */
  1759.     int     is_drag; /* If TRUE it's a drag event */
  1760.     int     jump_flags = 0; /* flags for jump_to_mouse() */
  1761.     FPOS    start_visual;
  1762.     FPOS    end_visual;
  1763.     int     diff;
  1764.     int     moved; /* Has cursor moved? */
  1765.     int     in_status_line; /* mouse in status line */
  1766.     int     c1, c2;
  1767.     int     VIsual_was_active = VIsual_active;
  1768.     int     regname;
  1769.     /*
  1770.      * When GUI is active, always recognize mouse events, otherwise:
  1771.      * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
  1772.      * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
  1773.      * - For command line and insert mode 'mouse' is checked before calling
  1774.      *  do_mouse().
  1775.      */
  1776.     if (do_always)
  1777. do_always = FALSE;
  1778.     else
  1779. #ifdef USE_GUI
  1780. if (!gui.in_use)
  1781. #endif
  1782. {
  1783.     if (VIsual_active)
  1784.     {
  1785. if (!mouse_has(MOUSE_VISUAL))
  1786.     return FALSE;
  1787.     }
  1788.     else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
  1789. return FALSE;
  1790. }
  1791.     which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
  1792.     /*
  1793.      * Ignore drag and release events if we didn't get a click.
  1794.      */
  1795.     if (is_click)
  1796. got_click = TRUE;
  1797.     else
  1798.     {
  1799. if (!got_click) /* didn't get click, ignore */
  1800.     return FALSE;
  1801. if (!is_drag) /* release, reset got_click */
  1802.     got_click = FALSE;
  1803.     }
  1804.     /*
  1805.      * ALT is currently ignored
  1806.      */
  1807.     if ((mod_mask & MOD_MASK_ALT))
  1808. return FALSE;
  1809.     /*
  1810.      * CTRL right mouse button does CTRL-T
  1811.      */
  1812.     if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
  1813.     {
  1814. if (State & INSERT)
  1815.     stuffcharReadbuff(Ctrl('O'));
  1816. stuffcharReadbuff(Ctrl('T'));
  1817. got_click = FALSE; /* ignore drag&release now */
  1818. return FALSE;
  1819.     }
  1820.     /*
  1821.      * CTRL only works with left mouse button
  1822.      */
  1823.     if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
  1824. return FALSE;
  1825.     /*
  1826.      * When a modifier is down, ignore drag and release events, as well as
  1827.      * multiple clicks and the middle mouse button.
  1828.      * Accept shift-leftmouse drags when 'M' option is in 'mouse'.
  1829.      */
  1830.     if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT))
  1831.     && (!is_click
  1832. || (mod_mask & MOD_MASK_MULTI_CLICK)
  1833. || which_button == MOUSE_MIDDLE)
  1834.     && !((mod_mask & MOD_MASK_SHIFT)
  1835. && mouse_model_popup()
  1836. && which_button == MOUSE_LEFT)
  1837.     )
  1838. return FALSE;
  1839.     /*
  1840.      * If the button press was used as the movement command for an operator
  1841.      * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
  1842.      * drag/release events.
  1843.      */
  1844.     if (!is_click && which_button == MOUSE_MIDDLE)
  1845. return FALSE;
  1846.     if (oap != NULL)
  1847. regname = oap->regname;
  1848.     else
  1849. regname = 0;
  1850.     /*
  1851.      * Middle mouse button does a 'put' of the selected text
  1852.      */
  1853.     if (which_button == MOUSE_MIDDLE)
  1854.     {
  1855. if (State == NORMAL)
  1856. {
  1857.     /*
  1858.      * If an operator was pending, we don't know what the user wanted
  1859.      * to do. Go back to normal mode: Clear the operator and beep().
  1860.      */
  1861.     if (oap != NULL && oap->op_type != OP_NOP)
  1862.     {
  1863. clearopbeep(oap);
  1864. return FALSE;
  1865.     }
  1866.     /*
  1867.      * If visual was active, yank the highlighted text and put it
  1868.      * before the mouse pointer position.
  1869.      */
  1870.     if (VIsual_active)
  1871.     {
  1872. stuffcharReadbuff('y');
  1873. stuffcharReadbuff(K_MIDDLEMOUSE);
  1874. do_always = TRUE; /* ignore 'mouse' setting next time */
  1875. return FALSE;
  1876.     }
  1877.     /*
  1878.      * The rest is below jump_to_mouse()
  1879.      */
  1880. }
  1881. /*
  1882.  * Middle click in insert mode doesn't move the mouse, just insert the
  1883.  * contents of a register.  '.' register is special, can't insert that
  1884.  * with do_put().
  1885.  */
  1886. else if (State & INSERT)
  1887. {
  1888.     if (regname == '.')
  1889. insert_reg(regname, TRUE);
  1890.     else
  1891.     {
  1892. #ifdef USE_CLIPBOARD
  1893. if (clipboard.available && regname == 0)
  1894.     regname = '*';
  1895. #endif
  1896. if (State == REPLACE && !yank_register_mline(regname))
  1897.     insert_reg(regname, TRUE);
  1898. else
  1899. {
  1900.     do_put(regname, BACKWARD, 1L, fix_indent | PUT_CURSEND);
  1901.     /* Repeat it with CTRL-R CTRL-R x.  Not exactly the same,
  1902.      * but mostly works fine. */
  1903.     AppendCharToRedobuff(Ctrl('R'));
  1904.     AppendCharToRedobuff(Ctrl('R'));
  1905.     AppendCharToRedobuff(regname == 0 ? '"' : regname);
  1906. }
  1907.     }
  1908.     return FALSE;
  1909. }
  1910. else
  1911.     return FALSE;
  1912.     }
  1913.     if (!is_click)
  1914. jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
  1915.     start_visual.lnum = 0;
  1916.     /*
  1917.      * When 'mousemodel' is "popup", translate mouse events:
  1918.      * right button up   -> pop-up menu
  1919.      * shift-left button -> right button
  1920.      */
  1921.     if (mouse_model_popup())
  1922.     {
  1923. if (which_button == MOUSE_RIGHT
  1924.     && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
  1925. {
  1926. #if defined(USE_GUI_MOTIF)
  1927.     /*
  1928.      * NOTE: Ignore right button down and drag mouse events.
  1929.      * Windows only shows the popup menu on the button up event.
  1930.      */
  1931.     if (is_click)
  1932. gui_show_popupmenu();
  1933. #endif
  1934. #if defined(USE_GUI_ATHENA) || defined(USE_GUI_WIN32)
  1935.     /*
  1936.      * NOTE: Ignore right button down and drag mouse events.
  1937.      * Windows only shows the popup menu on the button up event.
  1938.      */
  1939.     if (!is_click && !is_drag)
  1940. gui_show_popupmenu();
  1941. #endif
  1942.     return FALSE;
  1943. }
  1944. if (which_button == MOUSE_LEFT && (mod_mask & MOD_MASK_SHIFT))
  1945. {
  1946.     which_button = MOUSE_RIGHT;
  1947.     mod_mask &= ~ MOD_MASK_SHIFT;
  1948. }
  1949.     }
  1950.     if ((State & (NORMAL | INSERT))
  1951.     && !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
  1952.     {
  1953. if (which_button == MOUSE_LEFT)
  1954. {
  1955.     if (is_click)
  1956.     {
  1957. /* stop Visual mode for a left click in a window, but not when
  1958.  * on a status line */
  1959. if (VIsual_active)
  1960.     jump_flags |= MOUSE_MAY_STOP_VIS;
  1961.     }
  1962.     else
  1963. jump_flags |= MOUSE_MAY_VIS;
  1964. }
  1965. else if (which_button == MOUSE_RIGHT)
  1966. {
  1967.     if (is_click && VIsual_active)
  1968.     {
  1969. /*
  1970.  * Remember the start and end of visual before moving the
  1971.  * cursor.
  1972.  */
  1973. if (lt(curwin->w_cursor, VIsual))
  1974. {
  1975.     start_visual = curwin->w_cursor;
  1976.     end_visual = VIsual;
  1977. }
  1978. else
  1979. {
  1980.     start_visual = VIsual;
  1981.     end_visual = curwin->w_cursor;
  1982. }
  1983.     }
  1984.     jump_flags |= MOUSE_MAY_VIS;
  1985. }
  1986.     }
  1987.     /*
  1988.      * If an operator is pending, ignore all drags and releases until the
  1989.      * next mouse click.
  1990.      */
  1991.     if (!is_drag && oap != NULL && oap->op_type != OP_NOP)
  1992.     {
  1993. got_click = FALSE;
  1994. oap->motion_type = MCHAR;
  1995.     }
  1996.     /*
  1997.      * Jump!
  1998.      */
  1999.     jump_flags = jump_to_mouse(jump_flags,
  2000.       oap == NULL ? NULL : &(oap->inclusive));
  2001.     moved = (jump_flags & CURSOR_MOVED);
  2002.     in_status_line = ((jump_flags & IN_STATUS_LINE) == IN_STATUS_LINE);
  2003.     if (start_visual.lnum) /* right click in visual mode */
  2004.     {
  2005. /*
  2006.  * In Visual-block mode, divide the area in four, pick up the corner
  2007.  * that is in the quarter that the cursor is in.
  2008.  */
  2009. if (VIsual_mode == Ctrl('V'))
  2010. {
  2011.     colnr_t leftcol, rightcol;
  2012.     getvcols(&start_visual, &end_visual, &leftcol, &rightcol);
  2013.     if (curwin->w_curswant > (leftcol + rightcol) / 2)
  2014. end_visual.col = leftcol;
  2015.     else
  2016. end_visual.col = rightcol;
  2017.     if (curwin->w_cursor.lnum <
  2018.     (start_visual.lnum + end_visual.lnum) / 2)
  2019. end_visual.lnum = end_visual.lnum;
  2020.     else
  2021. end_visual.lnum = start_visual.lnum;
  2022.     /* move VIsual to the right column */
  2023.     start_visual = curwin->w_cursor;     /* save the cursor pos */
  2024.     curwin->w_cursor = end_visual;
  2025.     coladvance(end_visual.col);
  2026.     VIsual = curwin->w_cursor;
  2027.     curwin->w_cursor = start_visual;     /* restore the cursor */
  2028. }
  2029. else
  2030. {
  2031.     /*
  2032.      * If the click is before the start of visual, change the start.
  2033.      * If the click is after the end of visual, change the end.  If
  2034.      * the click is inside the visual, change the closest side.
  2035.      */
  2036.     if (lt(curwin->w_cursor, start_visual))
  2037. VIsual = end_visual;
  2038.     else if (lt(end_visual, curwin->w_cursor))
  2039. VIsual = start_visual;
  2040.     else
  2041.     {
  2042. /* In the same line, compare column number */
  2043. if (end_visual.lnum == start_visual.lnum)
  2044. {
  2045.     if (curwin->w_cursor.col - start_visual.col >
  2046.     end_visual.col - curwin->w_cursor.col)
  2047. VIsual = start_visual;
  2048.     else
  2049. VIsual = end_visual;
  2050. }
  2051. /* In different lines, compare line number */
  2052. else
  2053. {
  2054.     diff = (curwin->w_cursor.lnum - start_visual.lnum) -
  2055. (end_visual.lnum - curwin->w_cursor.lnum);
  2056.     if (diff > 0) /* closest to end */
  2057. VIsual = start_visual;
  2058.     else if (diff < 0) /* closest to start */
  2059. VIsual = end_visual;
  2060.     else /* in the middle line */
  2061.     {
  2062. if (curwin->w_cursor.col <
  2063. (start_visual.col + end_visual.col) / 2)
  2064.     VIsual = end_visual;
  2065. else
  2066.     VIsual = start_visual;
  2067.     }
  2068. }
  2069.     }
  2070. }
  2071.     }
  2072.     /*
  2073.      * If Visual mode started in insert mode, execute "CTRL-O"
  2074.      */
  2075.     else if ((State & INSERT) && VIsual_active)
  2076. stuffcharReadbuff(Ctrl('O'));
  2077.     /*
  2078.      * When the cursor has moved in insert mode, and something was inserted,
  2079.      * and there are several windows, need to redraw.
  2080.      */
  2081.     if (moved && (State & INSERT) && modified && firstwin->w_next != NULL)
  2082.     {
  2083. update_curbuf(NOT_VALID);
  2084. modified = FALSE;
  2085.     }
  2086.     /*
  2087.      * Middle mouse click: Put text before cursor.
  2088.      */
  2089.     if (which_button == MOUSE_MIDDLE)
  2090.     {
  2091. #ifdef USE_CLIPBOARD
  2092. if (clipboard.available && regname == 0)
  2093.     regname = '*';
  2094. #endif
  2095. if (yank_register_mline(regname))
  2096. {
  2097.     if (mouse_past_bottom)
  2098. dir = FORWARD;
  2099. }
  2100. else if (mouse_past_eol)
  2101.     dir = FORWARD;
  2102. if (fix_indent)
  2103. {
  2104.     c1 = (dir == BACKWARD) ? '[' : ']';
  2105.     c2 = 'p';
  2106. }
  2107. else
  2108. {
  2109.     c1 = (dir == FORWARD) ? 'p' : 'P';
  2110.     c2 = NUL;
  2111. }
  2112. prep_redo(regname, count, NUL, c1, c2, NUL);
  2113. /*
  2114.  * Remember where the paste started, so in edit() Insstart can be set
  2115.  * to this position
  2116.  */
  2117. if (restart_edit)
  2118.     where_paste_started = curwin->w_cursor;
  2119. do_put(regname, dir, count, fix_indent | PUT_CURSEND);
  2120.     }
  2121.     /*
  2122.      * Ctrl-Mouse click (or double click in a help window) jumps to the tag
  2123.      * under the mouse pointer.
  2124.      */
  2125.     else if ((mod_mask & MOD_MASK_CTRL)
  2126.   || (curbuf->b_help && (mod_mask & MOD_MASK_2CLICK)))
  2127.     {
  2128. if (State & INSERT)
  2129.     stuffcharReadbuff(Ctrl('O'));
  2130. stuffcharReadbuff(Ctrl(']'));
  2131. got_click = FALSE; /* ignore drag&release now */
  2132.     }
  2133.     /*
  2134.      * Shift-Mouse click searches for the next occurrence of the word under
  2135.      * the mouse pointer
  2136.      */
  2137.     else if ((mod_mask & MOD_MASK_SHIFT))
  2138.     {
  2139. if (State & INSERT || (VIsual_active && VIsual_select))
  2140.     stuffcharReadbuff(Ctrl('O'));
  2141. if (which_button == MOUSE_LEFT)
  2142.     stuffcharReadbuff('*');
  2143. else /* MOUSE_RIGHT */
  2144.     stuffcharReadbuff('#');
  2145.     }
  2146.     /* Handle double clicks, unless on status line */
  2147.     else if (in_status_line)
  2148. ;
  2149.     else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT)))
  2150.     {
  2151. if (is_click || !VIsual_active)
  2152. {
  2153.     if (VIsual_active)
  2154. orig_cursor = VIsual;
  2155.     else
  2156.     {
  2157. check_visual_highlight();
  2158. VIsual = curwin->w_cursor;
  2159. orig_cursor = VIsual;
  2160. VIsual_active = TRUE;
  2161. VIsual_reselect = TRUE;
  2162. /* start Select mode if 'selectmode' contains "mouse" */
  2163. may_start_select('o');
  2164. setmouse();
  2165. if (p_smd)
  2166.     redraw_cmdline = TRUE;  /* show visual mode later */
  2167.     }
  2168.     if (mod_mask & MOD_MASK_2CLICK)
  2169. VIsual_mode = 'v';
  2170.     else if (mod_mask & MOD_MASK_3CLICK)
  2171. VIsual_mode = 'V';
  2172.     else if (mod_mask & MOD_MASK_4CLICK)
  2173. VIsual_mode = Ctrl('V');
  2174. }
  2175. if (mod_mask & MOD_MASK_2CLICK)
  2176. {
  2177.     if (lt(curwin->w_cursor, orig_cursor))
  2178.     {
  2179. find_start_of_word(&curwin->w_cursor);
  2180. find_end_of_word(&VIsual);
  2181.     }
  2182.     else
  2183.     {
  2184. find_start_of_word(&VIsual);
  2185. find_end_of_word(&curwin->w_cursor);
  2186.     }
  2187.     curwin->w_set_curswant = TRUE;
  2188. }
  2189. if (is_click)
  2190.     update_curbuf(NOT_VALID);     /* update the inversion */
  2191.     }
  2192.     else if (VIsual_active && VIsual_was_active != VIsual_active)
  2193. VIsual_mode = 'v';
  2194.     return moved;
  2195. }
  2196.     static void
  2197. find_start_of_word(pos)
  2198.     FPOS    *pos;
  2199. {
  2200.     char_u  *ptr;
  2201.     int     cclass;
  2202.     ptr = ml_get(pos->lnum);
  2203.     cclass = get_mouse_class(ptr[pos->col]);
  2204.     /* Can't test pos->col >= 0 because pos->col is unsigned */
  2205.     while (pos->col > 0 && get_mouse_class(ptr[pos->col]) == cclass)
  2206. pos->col--;
  2207.     if (pos->col != 0 || get_mouse_class(ptr[0]) != cclass)
  2208. pos->col++;
  2209. }
  2210.     static void
  2211. find_end_of_word(pos)
  2212.     FPOS    *pos;
  2213. {
  2214.     char_u  *ptr;
  2215.     int     cclass;
  2216.     ptr = ml_get(pos->lnum);
  2217.     if (*p_sel == 'e' && pos->col)
  2218. pos->col--;
  2219.     cclass = get_mouse_class(ptr[pos->col]);
  2220.     while (ptr[pos->col] && get_mouse_class(ptr[pos->col]) == cclass)
  2221. pos->col++;
  2222.     if (*p_sel != 'e' && pos->col)
  2223. pos->col--;
  2224. }
  2225.     static int
  2226. get_mouse_class(c)
  2227.     int     c;
  2228. {
  2229.     if (c == ' ' || c == 't')
  2230. return ' ';
  2231.     if (vim_isIDc(c))
  2232. return 'a';
  2233.     /*
  2234.      * There are a few special cases where we want certain combinations of
  2235.      * characters to be considered as a single word.  These are things like
  2236.      * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
  2237.      * character is in it's own class.
  2238.      */
  2239.     if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
  2240. return '=';
  2241.     return c;
  2242. }
  2243. #endif /* USE_MOUSE */
  2244. /*
  2245.  * Check if  highlighting for visual mode is possible, give a warning message
  2246.  * if not.
  2247.  */
  2248.     void
  2249. check_visual_highlight()
  2250. {
  2251.     static int     did_check = FALSE;
  2252.     if (!did_check && hl_attr(HLF_V) == 0)
  2253. MSG("Warning: terminal cannot highlight");
  2254.     did_check = TRUE;
  2255. }
  2256. /*
  2257.  * End visual mode.  If we are using the GUI, and autoselect is set, then
  2258.  * remember what was selected in case we need to paste it somewhere while we
  2259.  * still own the selection.  This function should ALWAYS be called to end
  2260.  * visual mode.
  2261.  */
  2262.     void
  2263. end_visual_mode()
  2264. {
  2265. #ifdef USE_CLIPBOARD
  2266.     if (clipboard.available)
  2267. clip_auto_select();
  2268. #endif
  2269.     VIsual_active = FALSE;
  2270. #ifdef USE_MOUSE
  2271.     setmouse();
  2272. #endif
  2273.     /* Save the current VIsual area for '< and '> marks, and "gv" */
  2274.     curbuf->b_visual_start = VIsual;
  2275.     curbuf->b_visual_end = curwin->w_cursor;
  2276.     curbuf->b_visual_mode = VIsual_mode;
  2277.     if (p_smd)
  2278. clear_cmdline = TRUE; /* unshow visual mode later */
  2279.     /* Don't leave the cursor past the end of the line */
  2280.     if (curwin->w_cursor.col > 0 && *ml_get_cursor() == NUL)
  2281. --curwin->w_cursor.col;
  2282. }
  2283. /*
  2284.  * Find the identifier under or to the right of the cursor.  If none is
  2285.  * found and find_type has FIND_STRING, then find any non-white string.  The
  2286.  * length of the string is returned, or zero if no string is found.  If a
  2287.  * string is found, a pointer to the string is put in *string, but note that
  2288.  * the caller must use the length returned as this string may not be NUL
  2289.  * terminated.
  2290.  */
  2291.     int
  2292. find_ident_under_cursor(string, find_type)
  2293.     char_u  **string;
  2294.     int     find_type;
  2295. {
  2296.     char_u  *ptr;
  2297.     int     col = 0;     /* init to shut up GCC */
  2298.     int     i;
  2299.     /*
  2300.      * if i == 0: try to find an identifier
  2301.      * if i == 1: try to find any string
  2302.      */
  2303.     ptr = ml_get_curline();
  2304.     for (i = (find_type & FIND_IDENT) ? 0 : 1; i < 2; ++i)
  2305.     {
  2306. /*
  2307.  * skip to start of identifier/string
  2308.  */
  2309. col = curwin->w_cursor.col;
  2310. while (ptr[col] != NUL &&
  2311.     (i == 0 ? !vim_iswordc(ptr[col]) : vim_iswhite(ptr[col])))
  2312.     ++col;
  2313. /*
  2314.  * Back up to start of identifier/string. This doesn't match the
  2315.  * real vi but I like it a little better and it shouldn't bother
  2316.  * anyone.
  2317.  * When FIND_IDENT isn't defined, we backup until a blank.
  2318.  */
  2319. while (col > 0 && (i == 0 ? vim_iswordc(ptr[col - 1]) :
  2320.     (!vim_iswhite(ptr[col - 1]) &&
  2321.    (!(find_type & FIND_IDENT) || !vim_iswordc(ptr[col - 1])))))
  2322.     --col;
  2323. /*
  2324.  * if we don't want just any old string, or we've found an identifier,
  2325.  * stop searching.
  2326.  */
  2327. if (!(find_type & FIND_STRING) || vim_iswordc(ptr[col]))
  2328.     break;
  2329.     }
  2330.     /*
  2331.      * didn't find an identifier or string
  2332.      */
  2333.     if (ptr[col] == NUL || (!vim_iswordc(ptr[col]) && i == 0))
  2334.     {
  2335. if (find_type & FIND_STRING)
  2336.     EMSG("No string under cursor");
  2337. else
  2338.     EMSG("No identifier under cursor");
  2339. return 0;
  2340.     }
  2341.     ptr += col;
  2342.     *string = ptr;
  2343.     col = 0;
  2344.     while (i == 0 ? vim_iswordc(*ptr) : (*ptr != NUL && !vim_iswhite(*ptr)))
  2345.     {
  2346. ++ptr;
  2347. ++col;
  2348.     }
  2349.     return col;
  2350. }
  2351. /*
  2352.  * Prepare for redo of a normal command.
  2353.  */
  2354.     static void
  2355. prep_redo_cmd(cap)
  2356.     CMDARG  *cap;
  2357. {
  2358.     prep_redo(cap->oap->regname, cap->count0,
  2359.   NUL, cap->cmdchar, NUL, cap->nchar);
  2360. }
  2361. /*
  2362.  * Prepare for redo of any command.
  2363.  */
  2364.     static void
  2365. prep_redo(regname, num, prechar, cmd, c, nchar)
  2366.     int     regname;
  2367.     long    num;
  2368.     int     prechar;
  2369.     int     cmd;
  2370.     int     c;
  2371.     int     nchar;
  2372. {
  2373.     ResetRedobuff();
  2374.     if (regname != 0) /* yank from specified buffer */
  2375.     {
  2376. AppendCharToRedobuff('"');
  2377. AppendCharToRedobuff(regname);
  2378.     }
  2379.     if (num)
  2380. AppendNumberToRedobuff(num);
  2381.     if (prechar != NUL)
  2382. AppendCharToRedobuff(prechar);
  2383.     AppendCharToRedobuff(cmd);
  2384.     if (c != NUL)
  2385. AppendCharToRedobuff(c);
  2386.     if (nchar != NUL)
  2387. AppendCharToRedobuff(nchar);
  2388. }
  2389. /*
  2390.  * check for operator active and clear it
  2391.  *
  2392.  * return TRUE if operator was active
  2393.  */
  2394.     static int
  2395. checkclearop(oap)
  2396.     OPARG *oap;
  2397. {
  2398.     if (oap->op_type == OP_NOP)
  2399. return FALSE;
  2400.     clearopbeep(oap);
  2401.     return TRUE;
  2402. }
  2403. /*
  2404.  * check for operator or Visual active and clear it
  2405.  *
  2406.  * return TRUE if operator was active
  2407.  */
  2408.     static int
  2409. checkclearopq(oap)
  2410.     OPARG *oap;
  2411. {
  2412.     if (oap->op_type == OP_NOP && !VIsual_active)
  2413. return FALSE;
  2414.     clearopbeep(oap);
  2415.     return TRUE;
  2416. }
  2417.     static void
  2418. clearop(oap)
  2419.     OPARG *oap;
  2420. {
  2421.     oap->op_type = OP_NOP;
  2422.     oap->regname = 0;
  2423. }
  2424.     static void
  2425. clearopbeep(oap)
  2426.     OPARG *oap;
  2427. {
  2428.     clearop(oap);
  2429.     beep_flush();
  2430. }
  2431. #ifdef SHOWCMD
  2432. /*
  2433.  * Routines for displaying a partly typed command
  2434.  */
  2435. static char_u showcmd_buf[SHOWCMD_COLS + 1];
  2436. static char_u old_showcmd_buf[SHOWCMD_COLS + 1];  /* For push_showcmd() */
  2437. static int showcmd_is_clear = TRUE;
  2438. static void display_showcmd __ARGS((void));
  2439.     void
  2440. clear_showcmd()
  2441. {
  2442.     if (!p_sc)
  2443. return;
  2444.     showcmd_buf[0] = NUL;
  2445.     /*
  2446.      * Don't actually display something if there is nothing to clear.
  2447.      */
  2448.     if (showcmd_is_clear)
  2449. return;
  2450.     display_showcmd();
  2451. }
  2452. /*
  2453.  * Add 'c' to string of shown command chars.
  2454.  * Return TRUE if output has been written (and setcursor() has been called).
  2455.  */
  2456.     int
  2457. add_to_showcmd(c)
  2458.     int     c;
  2459. {
  2460.     char_u  *p;
  2461.     int     old_len;
  2462.     int     extra_len;
  2463.     int     overflow;
  2464.     int     i;
  2465.     static int     ignore[] =
  2466.        {K_SCROLLBAR, K_HORIZ_SCROLLBAR, K_IGNORE,
  2467. K_MIDDLEMOUSE, K_MIDDLEDRAG, K_MIDDLERELEASE,
  2468. K_LEFTMOUSE, K_LEFTDRAG, K_LEFTRELEASE,
  2469. K_RIGHTMOUSE, K_RIGHTDRAG, K_RIGHTRELEASE,
  2470. 0};
  2471.     if (!p_sc)
  2472. return FALSE;
  2473.     /* Ignore keys that are scrollbar updates and mouse clicks */
  2474.     for (i = 0; ignore[i]; ++i)
  2475. if (ignore[i] == c)
  2476.     return FALSE;
  2477.     p = transchar(c);
  2478.     old_len = STRLEN(showcmd_buf);
  2479.     extra_len = STRLEN(p);
  2480.     overflow = old_len + extra_len - SHOWCMD_COLS;
  2481.     if (overflow > 0)
  2482. STRCPY(showcmd_buf, showcmd_buf + overflow);
  2483.     STRCAT(showcmd_buf, p);
  2484.     if (char_avail())
  2485. return FALSE;
  2486.     display_showcmd();
  2487.     return TRUE;
  2488. }
  2489.     void
  2490. add_to_showcmd_c(c)
  2491.     int c;
  2492. {
  2493.     if (!add_to_showcmd(c))
  2494. setcursor();
  2495. }
  2496. /*
  2497.  * Delete 'len' characters from the end of the shown command.
  2498.  */
  2499.     static void
  2500. del_from_showcmd(len)
  2501.     int     len;
  2502. {
  2503.     int     old_len;
  2504.     if (!p_sc)
  2505. return;
  2506.     old_len = STRLEN(showcmd_buf);
  2507.     if (len > old_len)
  2508. len = old_len;
  2509.     showcmd_buf[old_len - len] = NUL;
  2510.     if (!char_avail())
  2511. display_showcmd();
  2512. }
  2513.     void
  2514. push_showcmd()
  2515. {
  2516.     if (p_sc)
  2517. STRCPY(old_showcmd_buf, showcmd_buf);
  2518. }
  2519.     void
  2520. pop_showcmd()
  2521. {
  2522.     if (!p_sc)
  2523. return;
  2524.     STRCPY(showcmd_buf, old_showcmd_buf);
  2525.     display_showcmd();
  2526. }
  2527.     static void
  2528. display_showcmd()
  2529. {
  2530.     int     len;
  2531.     cursor_off();
  2532.     len = STRLEN(showcmd_buf);
  2533.     if (len == 0)
  2534. showcmd_is_clear = TRUE;
  2535.     else
  2536.     {
  2537. screen_puts(showcmd_buf, (int)Rows - 1, sc_col, 0);
  2538. showcmd_is_clear = FALSE;
  2539.     }
  2540.     /*
  2541.      * clear the rest of an old message by outputing up to SHOWCMD_COLS spaces
  2542.      */
  2543.     screen_puts((char_u *)"          " + len, (int)Rows - 1, sc_col + len, 0);
  2544.     setcursor();     /* put cursor back where it belongs */
  2545. }
  2546. #endif
  2547. /*
  2548.  * Implementation of "gd" and "gD" command.
  2549.  */
  2550.     static void
  2551. nv_gd(oap, nchar)
  2552.     OPARG   *oap;
  2553.     int     nchar;
  2554. {
  2555.     int len;
  2556.     char_u *pat;
  2557.     FPOS old_pos;
  2558.     int t;
  2559.     int save_p_ws;
  2560.     int save_p_scs;
  2561.     char_u *ptr;
  2562.     if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 ||
  2563.        (pat = alloc(len + 5)) == NULL)
  2564.     {
  2565. clearopbeep(oap);
  2566. return;
  2567.     }
  2568.     sprintf((char *)pat, vim_iswordc(*ptr) ? "\<%.*s\>" :
  2569.     "%.*s", len, ptr);
  2570.     old_pos = curwin->w_cursor;
  2571.     save_p_ws = p_ws;
  2572.     save_p_scs = p_scs;
  2573.     p_ws = FALSE; /* don't wrap around end of file now */
  2574.     p_scs = FALSE; /* don't switch ignorecase off now */
  2575.     fo_do_comments = TRUE;
  2576.     /*
  2577.      * Search back for the end of the previous function.
  2578.      * If this fails, and with "gD", go to line 1.
  2579.      * Search forward for the identifier, ignore comment lines.
  2580.      */
  2581.     if (nchar == 'D' || !findpar(oap, BACKWARD, 1L, '}', FALSE))
  2582.     {
  2583. setpcmark(); /* Set in findpar() otherwise */
  2584. curwin->w_cursor.lnum = 1;
  2585.     }
  2586.     while ((t = searchit(curbuf, &curwin->w_cursor, FORWARD, pat, 1L, 0,
  2587. RE_LAST)) == OK &&
  2588.     get_leader_len(ml_get_curline(), NULL) &&
  2589.     old_pos.lnum > curwin->w_cursor.lnum)
  2590. ++curwin->w_cursor.lnum;
  2591.     if (t == FAIL || old_pos.lnum <= curwin->w_cursor.lnum)
  2592.     {
  2593. clearopbeep(oap);
  2594. curwin->w_cursor = old_pos;
  2595.     }
  2596.     else
  2597. curwin->w_set_curswant = TRUE;
  2598.     vim_free(pat);
  2599.     p_ws = save_p_ws;
  2600.     p_scs = save_p_scs;
  2601.     fo_do_comments = FALSE;
  2602. }
  2603. /*
  2604.  * Move 'dist' lines in direction 'dir', counting lines by *screen*
  2605.  * lines rather than lines in the file.
  2606.  * 'dist' must be positive.
  2607.  *
  2608.  * Return OK if able to move cursor, FAIL otherwise.
  2609.  */
  2610.     static int
  2611. nv_screengo(oap, dir, dist)
  2612.     OPARG   *oap;
  2613.     int     dir;
  2614.     long    dist;
  2615. {
  2616.     int linelen = linetabsize(ml_get_curline());
  2617.     int retval = OK;
  2618.     int atend = FALSE;
  2619.     int n;
  2620.     oap->motion_type = MCHAR;
  2621.     oap->inclusive = FALSE;
  2622.     /*
  2623.      * Instead of sticking at the last character of the line in the file we
  2624.      * try to stick in the last column of the screen
  2625.      */
  2626.     if (curwin->w_curswant == MAXCOL)
  2627.     {
  2628. atend = TRUE;
  2629. validate_virtcol();
  2630. curwin->w_curswant = ((curwin->w_virtcol +
  2631.        (curwin->w_p_nu ? 8 : 0)) / Columns + 1) * Columns - 1;
  2632. if (curwin->w_p_nu && curwin->w_curswant > 8)
  2633.     curwin->w_curswant -= 8;
  2634.     }
  2635.     else
  2636. while (curwin->w_curswant >= (colnr_t)(linelen + Columns))
  2637.     curwin->w_curswant -= Columns;
  2638.     while (dist--)
  2639.     {
  2640. if (dir == BACKWARD)
  2641. {
  2642. /* move back within line */
  2643.     if ((long)curwin->w_curswant >= Columns)
  2644. curwin->w_curswant -= Columns;
  2645.     else /* to previous line */
  2646.     {
  2647. if (curwin->w_cursor.lnum == 1)
  2648. {
  2649.     retval = FAIL;
  2650.     break;
  2651. }
  2652. --curwin->w_cursor.lnum;
  2653. linelen = linetabsize(ml_get_curline());
  2654. n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns)
  2655.     * Columns;
  2656. if (curwin->w_p_nu &&
  2657.  (long)curwin->w_curswant >= Columns - 8 && n)
  2658.     n -= Columns;
  2659. curwin->w_curswant += n;
  2660.     }
  2661. }
  2662. else /* dir == FORWARD */
  2663. {
  2664.     n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns) * Columns;
  2665.     if (curwin->w_p_nu && n > 8)
  2666. n -= 8;
  2667. /* move forward within line */
  2668.     if (curwin->w_curswant < (colnr_t)n)
  2669. curwin->w_curswant += Columns;
  2670.     else /* to next line */
  2671.     {
  2672. if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  2673. {
  2674.     retval = FAIL;
  2675.     break;
  2676. }
  2677. curwin->w_cursor.lnum++;
  2678. linelen = linetabsize(ml_get_curline());
  2679. curwin->w_curswant %= Columns;
  2680.     }
  2681. }
  2682.     }
  2683.     coladvance(curwin->w_curswant);
  2684.     if (atend)
  2685. curwin->w_curswant = MAXCOL;     /* stick in the last column */
  2686.     return retval;
  2687. }
  2688. /*
  2689.  * Handle CTRL-E and CTRL-Y commands: scroll a line up or down.
  2690.  */
  2691.     static void
  2692. nv_scroll_line(cap, is_ctrl_e)
  2693.     CMDARG  *cap;
  2694.     int     is_ctrl_e;     /* TRUE for CTRL-E command */
  2695. {
  2696.     linenr_t     prev_topline = curwin->w_topline;
  2697.     if (checkclearop(cap->oap))
  2698. return;
  2699.     if (is_ctrl_e)
  2700. scrollup(cap->count1);
  2701.     else
  2702. scrolldown(cap->count1);
  2703.     if (p_so)
  2704.     {
  2705. cursor_correct();
  2706. update_topline();
  2707. /* If moved back to where we were, at least move the cursor, otherwise
  2708.  * we get stuck at one position.  Don't move the cursor up if the
  2709.  * first line of the buffer is already on the screen */
  2710. if (curwin->w_topline == prev_topline)
  2711. {
  2712.     if (is_ctrl_e)
  2713. cursor_down(1L, FALSE);
  2714.     else if (prev_topline != 1L)
  2715. cursor_up(1L, FALSE);
  2716. }
  2717.     }
  2718.     coladvance(curwin->w_curswant);
  2719.     update_screen(VALID);
  2720. }
  2721.     static void
  2722. nv_zet(cap)
  2723.     CMDARG  *cap;
  2724. {
  2725.     long n;
  2726.     colnr_t col;
  2727.     int nchar = cap->nchar;
  2728.     if (vim_isdigit(nchar))
  2729.     {
  2730. n = nchar - '0';
  2731. for (;;)
  2732. {
  2733. #ifdef USE_GUI_WIN32
  2734.     dont_scroll = TRUE; /* disallow scrolling here */
  2735. #endif
  2736.     ++no_mapping;
  2737.     ++allow_keys;   /* no mapping for nchar, but allow key codes */
  2738.     nchar = vgetc();
  2739. #ifdef HAVE_LANGMAP
  2740.     LANGMAP_ADJUST(nchar, TRUE);
  2741. #endif
  2742.     --no_mapping;
  2743.     --allow_keys;
  2744. #ifdef SHOWCMD
  2745.     (void)add_to_showcmd(nchar);
  2746. #endif
  2747.     if (nchar == K_DEL)
  2748. n /= 10;
  2749.     else if (vim_isdigit(nchar))
  2750. n = n * 10 + (nchar - '0');
  2751.     else if (nchar == CR)
  2752.     {
  2753. #ifdef USE_GUI
  2754. need_mouse_correct = TRUE;
  2755. #endif
  2756. win_setheight((int)n);
  2757. break;
  2758.     }
  2759.     else if (nchar == 'l' || nchar == 'h' ||
  2760.   nchar == K_LEFT || nchar == K_RIGHT)
  2761.     {
  2762. cap->count1 = n ? n * cap->count1 : cap->count1;
  2763. goto dozet;
  2764.     }
  2765.     else
  2766.     {
  2767. clearopbeep(cap->oap);
  2768. break;
  2769.     }
  2770. }
  2771. cap->oap->op_type = OP_NOP;
  2772. return;
  2773.     }
  2774. dozet:
  2775.     /*
  2776.      * If line number given, set cursor, except for "zh", "zl", "ze" and
  2777.      * "zs"
  2778.      */
  2779.     if (       vim_strchr((char_u *)"hles", nchar) == NULL
  2780.     && nchar != K_LEFT
  2781.     && nchar != K_RIGHT
  2782.     && cap->count0
  2783.     && cap->count0 != curwin->w_cursor.lnum)
  2784.     {
  2785. setpcmark();
  2786. if (cap->count0 > curbuf->b_ml.ml_line_count)
  2787.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2788. else
  2789.     curwin->w_cursor.lnum = cap->count0;
  2790.     }
  2791.     switch (nchar)
  2792.     {
  2793.     case NL:     /* put curwin->w_cursor at top of screen */
  2794.     case CR:
  2795. beginline(BL_WHITE | BL_FIX);
  2796. /* FALLTHROUGH */
  2797.     case 't':
  2798. scroll_cursor_top(0, TRUE);
  2799. break;
  2800.     case '.': /* put curwin->w_cursor in middle of screen */
  2801. beginline(BL_WHITE | BL_FIX);
  2802. /* FALLTHROUGH */
  2803.     case 'z':
  2804. scroll_cursor_halfway(TRUE);
  2805. break;
  2806.     case '-': /* put curwin->w_cursor at bottom of screen */
  2807. beginline(BL_WHITE | BL_FIX);
  2808. /* FALLTHROUGH */
  2809.     case 'b':
  2810. scroll_cursor_bot(0, TRUE);
  2811. break;
  2812. /* "zh" - scroll screen to the right */
  2813.     case 'h':
  2814.     case K_LEFT:
  2815. if (!curwin->w_p_wrap)
  2816. {
  2817.     if ((colnr_t)cap->count1 > curwin->w_leftcol)
  2818. curwin->w_leftcol = 0;
  2819.     else
  2820. curwin->w_leftcol -= (colnr_t)cap->count1;
  2821.     leftcol_changed();
  2822. }
  2823. break;
  2824. /* "zl" - scroll screen to the left */
  2825.     case 'l':
  2826.     case K_RIGHT:
  2827. if (!curwin->w_p_wrap)
  2828. {
  2829.     /* scroll the window left */
  2830.     curwin->w_leftcol += (colnr_t)cap->count1;
  2831.     leftcol_changed();
  2832. }
  2833. break;
  2834. /* "zs" - scroll screen, cursor at the start */
  2835.     case 's':
  2836. if (!curwin->w_p_wrap)
  2837. {
  2838.     getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
  2839.     curwin->w_leftcol = col;
  2840.     redraw_later(NOT_VALID);
  2841. }
  2842. break;
  2843. /* "ze" - scroll screen, cursor at the end */
  2844.     case 'e':
  2845. if (!curwin->w_p_wrap)
  2846. {
  2847.     getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
  2848.     if ((long)col < Columns)
  2849. curwin->w_leftcol = 0;
  2850.     else
  2851. curwin->w_leftcol = col - Columns + 1;
  2852.     redraw_later(NOT_VALID);
  2853. }
  2854. break;
  2855.     case Ctrl('S'): /* ignore CTRL-S and CTRL-Q to avoid problems */
  2856.     case Ctrl('Q'): /* with terminals that use xon/xoff */
  2857. break;
  2858.     default:
  2859. clearopbeep(cap->oap);
  2860.     }
  2861.     update_screen(VALID);
  2862. }
  2863. /*
  2864.  * Handle a ":" command.
  2865.  */
  2866.     static void
  2867. nv_colon(cap)
  2868.     CMDARG  *cap;
  2869. {
  2870.     int     old_p_im;
  2871.     if (VIsual_active)
  2872. nv_operator(cap);
  2873.     else if (!checkclearop(cap->oap))
  2874.     {
  2875. /* translate "count:" into ":.,.+(count - 1)" */
  2876. if (cap->count0)
  2877. {
  2878.     stuffcharReadbuff('.');
  2879.     if (cap->count0 > 1)
  2880.     {
  2881. stuffReadbuff((char_u *)",.+");
  2882. stuffnumReadbuff((long)cap->count0 - 1L);
  2883.     }
  2884. }
  2885. /* When typing, don't type below an old message */
  2886. if (KeyTyped)
  2887.     compute_cmdrow();
  2888. old_p_im = p_im;
  2889. /* get a command line and execute it */
  2890. do_cmdline(NULL, getexline, NULL, 0);
  2891. /* If 'insertmode' changed, enter or exit Insert mode */
  2892. if (p_im != old_p_im)
  2893. {
  2894.     if (p_im)
  2895. restart_edit = 'i';
  2896.     else
  2897. restart_edit = 0;
  2898. }
  2899.     }
  2900. }
  2901. /*
  2902.  * Handle CTRL-G command.
  2903.  */
  2904.     static void
  2905. nv_ctrlg(cap)
  2906.     CMDARG *cap;
  2907. {
  2908.     if (VIsual_active) /* toggle Selection/Visual mode */
  2909.     {
  2910. VIsual_select = !VIsual_select;
  2911. showmode();
  2912.     }
  2913.     else if (!checkclearop(cap->oap))
  2914. /* print full name if count given or :cd used */
  2915. fileinfo((int)cap->count0, FALSE, FALSE);
  2916. }
  2917. /*
  2918.  * "ZZ": write if changed, and exit window
  2919.  * "ZQ": quit window (Elvis compatible)
  2920.  */
  2921.     static void
  2922. nv_zzet(cap)
  2923.     CMDARG *cap;
  2924. {
  2925.     if (!checkclearopq(cap->oap))
  2926.     {
  2927. if (cap->nchar == 'Z')
  2928.     stuffReadbuff((char_u *)":xn");
  2929. else if (cap->nchar == 'Q')
  2930.     stuffReadbuff((char_u *)":q!n");
  2931. else
  2932.     clearopbeep(cap->oap);
  2933.     }
  2934. }
  2935. /*
  2936.  * Handle the commands that use the word under the cursor.
  2937.  *
  2938.  * Returns TRUE for "*" and "#" commands, indicating that the next search
  2939.  * should not set the pcmark.
  2940.  */
  2941.     static void
  2942. nv_ident(cap, searchp)
  2943.     CMDARG *cap;
  2944.     char_u **searchp;
  2945. {
  2946.     char_u *ptr = NULL;
  2947.     int n = 0; /* init for GCC */
  2948.     int cmdchar;
  2949.     int g_cmd; /* "g" command */
  2950.     char_u *aux_ptr;
  2951.     int isman;
  2952.     int isman_s;
  2953.     if (cap->cmdchar == 'g') /* "g*", "g#", "g]" and "gCTRL-]" */
  2954.     {
  2955. cmdchar = cap->nchar;
  2956. g_cmd = TRUE;
  2957.     }
  2958.     else
  2959.     {
  2960. cmdchar = cap->cmdchar;
  2961. g_cmd = FALSE;
  2962.     }
  2963.     /*
  2964.      * The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
  2965.      */
  2966.     if (cmdchar == ']' || cmdchar == Ctrl(']') || cmdchar == 'K')
  2967.     {
  2968. if (VIsual_active) /* :ta to visual highlighted text */
  2969. {
  2970.     if (VIsual.lnum != curwin->w_cursor.lnum)
  2971.     {
  2972. clearopbeep(cap->oap);
  2973. return;
  2974.     }
  2975.     if (lt(curwin->w_cursor, VIsual))
  2976.     {
  2977. ptr = ml_get_pos(&curwin->w_cursor);
  2978. n = VIsual.col - curwin->w_cursor.col + 1;
  2979.     }
  2980.     else
  2981.     {
  2982. ptr = ml_get_pos(&VIsual);
  2983. n = curwin->w_cursor.col - VIsual.col + 1;
  2984.     }
  2985.     end_visual_mode();
  2986.     VIsual_reselect = FALSE;
  2987.     redraw_curbuf_later(NOT_VALID);    /* update the inversion later */
  2988. }
  2989. if (checkclearopq(cap->oap))
  2990.     return;
  2991.     }
  2992.     if (ptr == NULL && (n = find_ident_under_cursor(&ptr,
  2993.     (cmdchar == '*' || cmdchar == '#')
  2994.  ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
  2995.     {
  2996. clearop(cap->oap);
  2997. return;
  2998.     }
  2999.     isman = (STRCMP(p_kp, "man") == 0);
  3000.     isman_s = (STRCMP(p_kp, "man -s") == 0);
  3001.     if (cap->count0 && !(cmdchar == 'K' && (isman || isman_s))
  3002.     && !(cmdchar == '*' || cmdchar == '#'))
  3003. stuffnumReadbuff(cap->count0);
  3004.     switch (cmdchar)
  3005.     {
  3006. case '*':
  3007. case '#':
  3008.     /*
  3009.      * Put cursor at start of word, makes search skip the word
  3010.      * under the cursor.
  3011.      * Call setpcmark() first, so "*``" puts the cursor back where
  3012.      * it was.
  3013.      */
  3014.     setpcmark();
  3015.     curwin->w_cursor.col = ptr - ml_get_curline();
  3016.     if (!g_cmd && vim_iswordc(*ptr))
  3017. stuffReadbuff((char_u *)"\<");
  3018.     no_smartcase = TRUE; /* don't use 'smartcase' now */
  3019.     break;
  3020. case 'K':
  3021.     if (*p_kp == NUL)
  3022. stuffReadbuff((char_u *)":he ");
  3023.     else
  3024.     {
  3025. stuffReadbuff((char_u *)":! ");
  3026. if (!cap->count0 && isman_s)
  3027.     stuffReadbuff((char_u *)"man");
  3028. else
  3029.     stuffReadbuff(p_kp);
  3030. stuffReadbuff((char_u *)" ");
  3031. if (cap->count0 && (isman || isman_s))
  3032. {
  3033.     stuffnumReadbuff(cap->count0);
  3034.     stuffReadbuff((char_u *)" ");
  3035. }
  3036.     }
  3037.     break;
  3038. case ']':
  3039. #ifdef USE_CSCOPE
  3040.     if (p_cst)
  3041. stuffReadbuff((char_u *)":cstag ");
  3042.     else
  3043. #endif
  3044.     stuffReadbuff((char_u *)":ts ");
  3045.     break;
  3046. default:
  3047.     if (curbuf->b_help)
  3048. stuffReadbuff((char_u *)":he ");
  3049.     else if (g_cmd)
  3050. stuffReadbuff((char_u *)":tj ");
  3051.     else
  3052. stuffReadbuff((char_u *)":ta ");
  3053.     }
  3054.     /*
  3055.      * Now grab the chars in the identifier
  3056.      */
  3057.     if (cmdchar == '*' || cmdchar == '#')
  3058. aux_ptr = (char_u *)(p_magic ? "/?.*~[^$\" : "/?^$\");
  3059.     else
  3060. aux_ptr = escape_chars;
  3061.     while (n--)
  3062.     {
  3063. /* put a backslash before  and some others */
  3064. if (vim_strchr(aux_ptr, *ptr) != NULL)
  3065.     stuffcharReadbuff('\');
  3066. /* don't interpret the characters as edit commands */
  3067. else if (*ptr < ' ' || *ptr > '~')
  3068.     stuffcharReadbuff(Ctrl('V'));
  3069. stuffcharReadbuff(*ptr++);
  3070.     }
  3071.     if (       !g_cmd
  3072.     && (cmdchar == '*' || cmdchar == '#')
  3073.     && vim_iswordc(ptr[-1]))
  3074. stuffReadbuff((char_u *)"\>");
  3075.     stuffReadbuff((char_u *)"n");
  3076.     /*
  3077.      * The search commands may be given after an operator.  Therefore they
  3078.      * must be executed right now.
  3079.      */
  3080.     if (cmdchar == '*' || cmdchar == '#')
  3081.     {
  3082. if (cmdchar == '*')
  3083.     cap->cmdchar = '/';
  3084. else
  3085.     cap->cmdchar = '?';
  3086. nv_search(cap, searchp, TRUE);
  3087.     }
  3088. }
  3089. /*
  3090.  * Handle scrolling command 'H', 'L' and 'M'.
  3091.  */
  3092.     static void
  3093. nv_scroll(cap)
  3094.     CMDARG  *cap;
  3095. {
  3096.     int     used = 0;
  3097.     long    n;
  3098.     cap->oap->motion_type = MLINE;
  3099.     setpcmark();
  3100.     if (cap->cmdchar == 'L')
  3101.     {
  3102. validate_botline();     /* make sure curwin->w_botline is valid */
  3103. curwin->w_cursor.lnum = curwin->w_botline - 1;
  3104. if (cap->count1 - 1 >= curwin->w_cursor.lnum)
  3105.     curwin->w_cursor.lnum = 1;
  3106. else
  3107.     curwin->w_cursor.lnum -= cap->count1 - 1;
  3108.     }
  3109.     else
  3110.     {
  3111. if (cap->cmdchar == 'M')
  3112. {
  3113.     validate_botline();     /* make sure w_empty_rows is valid */
  3114.     for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
  3115. if ((used += plines(curwin->w_topline + n)) >=
  3116.     (curwin->w_height - curwin->w_empty_rows + 1) / 2)
  3117.     break;
  3118.     if (n && used > curwin->w_height)
  3119. --n;
  3120. }
  3121. else
  3122.     n = cap->count1 - 1;
  3123. curwin->w_cursor.lnum = curwin->w_topline + n;
  3124. if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3125.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3126.     }
  3127.     cursor_correct(); /* correct for 'so' */
  3128.     beginline(BL_SOL | BL_FIX);
  3129. }
  3130. /*
  3131.  * Cursor right commands.
  3132.  */
  3133.     static void
  3134. nv_right(cap)
  3135.     CMDARG *cap;
  3136. {
  3137.     long n;
  3138.     int past_line;
  3139.     cap->oap->motion_type = MCHAR;
  3140.     cap->oap->inclusive = FALSE;
  3141.     past_line = (VIsual_active && *p_sel != 'o');
  3142.     for (n = cap->count1; n > 0; --n)
  3143.     {
  3144. if ((!past_line && oneright() == FAIL)
  3145. || (past_line && *ml_get_cursor() == NUL))
  3146. {
  3147.     /*
  3148.      *   <Space> wraps to next line if 'whichwrap' bit 1 set.
  3149.      *       'l' wraps to next line if 'whichwrap' bit 2 set.
  3150.      * CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set
  3151.      */
  3152.     if (       ((cap->cmdchar == ' '
  3153.     && vim_strchr(p_ww, 's') != NULL)
  3154. || (cap->cmdchar == 'l'
  3155.     && vim_strchr(p_ww, 'l') != NULL)
  3156. || (cap->cmdchar == K_RIGHT
  3157.     && vim_strchr(p_ww, '>') != NULL))
  3158.     && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  3159.     {
  3160. /* When deleting we also count the NL as a character.
  3161.  * Set cap->oap->inclusive when last char in the line is
  3162.  * included, move to next line after that */
  3163. if (    (cap->oap->op_type == OP_DELETE
  3164.     || cap->oap->op_type == OP_CHANGE)
  3165. && !cap->oap->inclusive
  3166. && !lineempty(curwin->w_cursor.lnum))
  3167.     cap->oap->inclusive = TRUE;
  3168. else
  3169. {
  3170.     ++curwin->w_cursor.lnum;
  3171.     curwin->w_cursor.col = 0;
  3172.     curwin->w_set_curswant = TRUE;
  3173.     cap->oap->inclusive = FALSE;
  3174. }
  3175. continue;
  3176.     }
  3177.     if (cap->oap->op_type == OP_NOP)
  3178.     {
  3179. /* Only beep and flush if not moved at all */
  3180. if (n == cap->count1)
  3181.     beep_flush();
  3182.     }
  3183.     else
  3184.     {
  3185. if (!lineempty(curwin->w_cursor.lnum))
  3186.     cap->oap->inclusive = TRUE;
  3187.     }
  3188.     break;
  3189. }
  3190. else if (past_line)
  3191. {
  3192.     curwin->w_set_curswant = TRUE;
  3193.     ++curwin->w_cursor.col;
  3194. }
  3195.     }
  3196. }
  3197. /*
  3198.  * Cursor left commands.
  3199.  *
  3200.  * Returns TRUE when operator end should not be adjusted.
  3201.  */
  3202.     static int
  3203. nv_left(cap)
  3204.     CMDARG *cap;
  3205. {
  3206.     long n;
  3207.     int retval = FALSE;
  3208.     cap->oap->motion_type = MCHAR;
  3209.     cap->oap->inclusive = FALSE;
  3210.     for (n = cap->count1; n > 0; --n)
  3211.     {
  3212. if (oneleft() == FAIL)
  3213. {
  3214.     /* <BS> and <Del> wrap to previous line if 'whichwrap' has 'b'.
  3215.      *  'h' wraps to previous line if 'whichwrap' has 'h'.
  3216.      *    CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
  3217.      */
  3218.     if (       (((cap->cmdchar == K_BS
  3219. || cap->cmdchar == Ctrl('H'))
  3220.     && vim_strchr(p_ww, 'b') != NULL)
  3221. || (cap->cmdchar == 'h'
  3222.     && vim_strchr(p_ww, 'h') != NULL)
  3223. || (cap->cmdchar == K_LEFT
  3224.     && vim_strchr(p_ww, '<') != NULL))
  3225.     && curwin->w_cursor.lnum > 1)
  3226.     {
  3227. --(curwin->w_cursor.lnum);
  3228. coladvance(MAXCOL);
  3229. curwin->w_set_curswant = TRUE;
  3230. /* When the NL before the first char has to be deleted we
  3231.  * put the cursor on the NUL after the previous line.
  3232.  * This is a very special case, be careful!
  3233.  * don't adjust op_end now, otherwise it won't work */
  3234. if (    (cap->oap->op_type == OP_DELETE
  3235.     || cap->oap->op_type == OP_CHANGE)
  3236. && !lineempty(curwin->w_cursor.lnum))
  3237. {
  3238.     ++curwin->w_cursor.col;
  3239.     retval = TRUE;
  3240. }
  3241. continue;
  3242.     }
  3243.     /* Only beep and flush if not moved at all */
  3244.     else if (cap->oap->op_type == OP_NOP && n == cap->count1)
  3245. beep_flush();
  3246.     break;
  3247. }
  3248.     }
  3249.     return retval;
  3250. }
  3251. #ifdef FILE_IN_PATH
  3252. /*
  3253.  * Grab the file name under the cursor and edit it.
  3254.  */
  3255.     static void
  3256. nv_gotofile(cap)
  3257.     CMDARG *cap;
  3258. {
  3259.     char_u *ptr;
  3260.     ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP, cap->count1);
  3261.     if (ptr != NULL)
  3262.     {
  3263. /* do autowrite if necessary */
  3264. if (curbuf_changed() && curbuf->b_nwindows <= 1 && !p_hid)
  3265.     autowrite(curbuf, FALSE);
  3266. setpcmark();
  3267. (void)do_ecmd(0, ptr, NULL, NULL, (linenr_t)0, p_hid ? ECMD_HIDE : 0);
  3268. vim_free(ptr);
  3269.     }
  3270.     else
  3271. clearop(cap->oap);
  3272. }
  3273. #endif
  3274. /*
  3275.  * Implementation of '?' and '/' commands.
  3276.  */
  3277.     static void
  3278. nv_search(cap, searchp, dont_set_mark)
  3279.     CMDARG     *cap;
  3280.     char_u     **searchp;
  3281.     int     dont_set_mark; /* don't set PC mark */
  3282. {
  3283.     OPARG *oap = cap->oap;
  3284.     int i;
  3285.     if ((*searchp = getcmdline(cap->cmdchar, cap->count1, 0)) == NULL)
  3286.     {
  3287. clearop(oap);
  3288. return;
  3289.     }
  3290.     oap->motion_type = MCHAR;
  3291.     oap->inclusive = FALSE;
  3292.     curwin->w_set_curswant = TRUE;
  3293.     i = do_search(oap, cap->cmdchar, *searchp, cap->count1,
  3294.     (dont_set_mark ? 0 : SEARCH_MARK) |
  3295.     SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG);
  3296.     if (i == 0)
  3297. clearop(oap);
  3298.     else if (i == 2)
  3299. oap->motion_type = MLINE;
  3300.     /* "/$" will put the cursor after the end of the line, may need to
  3301.      * correct that here */
  3302.     adjust_cursor();
  3303. }
  3304. /*
  3305.  * Handle "N" and "n" commands.
  3306.  */
  3307.     static void
  3308. nv_next(cap, flag)
  3309.     CMDARG *cap;
  3310.     int flag;
  3311. {
  3312.     cap->oap->motion_type = MCHAR;
  3313.     cap->oap->inclusive = FALSE;
  3314.     curwin->w_set_curswant = TRUE;
  3315.     if (!do_search(cap->oap, 0, NULL, cap->count1,
  3316.       SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG | flag))
  3317. clearop(cap->oap);
  3318.     /* "/$" will put the cursor after the end of the line, may need to
  3319.      * correct that here */
  3320.     adjust_cursor();
  3321. }
  3322.     static void
  3323. nv_csearch(cap, dir, type)
  3324.     CMDARG *cap;
  3325.     int dir;
  3326.     int type;
  3327. {
  3328.     cap->oap->motion_type = MCHAR;
  3329.     if (dir == BACKWARD)
  3330. cap->oap->inclusive = FALSE;
  3331.     else
  3332. cap->oap->inclusive = TRUE;
  3333.     curwin->w_set_curswant = TRUE;
  3334.     if (cap->nchar >= 0x100 || !searchc(cap->nchar, dir, type, cap->count1))
  3335. clearopbeep(cap->oap);
  3336.     else
  3337. adjust_for_sel(cap);
  3338. }
  3339.     static void
  3340. nv_brackets(cap, dir)
  3341.     CMDARG *cap;
  3342.     int dir;     /* BACKWARD or FORWARD */
  3343. {
  3344.     FPOS new_pos;
  3345.     FPOS *pos = NULL;     /* init for GCC */
  3346.     FPOS old_pos;     /* cursor position before command */
  3347.     int flag;
  3348.     long n;
  3349.     cap->oap->motion_type = MCHAR;
  3350.     cap->oap->inclusive = FALSE;
  3351.     old_pos = curwin->w_cursor;
  3352. #ifdef FILE_IN_PATH
  3353.     /*
  3354.      * "[f" or "]f" : Edit file under the cursor (same as "gf")
  3355.      */
  3356.     if (cap->nchar == 'f')
  3357. nv_gotofile(cap);
  3358.     else
  3359. #endif
  3360. #ifdef FIND_IN_PATH
  3361.     /*
  3362.      * Find the occurence(s) of the identifier or define under cursor
  3363.      * in current and included files or jump to the first occurence.
  3364.      *
  3365.      * search      list     jump
  3366.      *       fwd   bwd    fwd  bwd  fwd bwd
  3367.      * identifier     "]i"  "[i"   "]I"  "[I" "]^I"  "[^I"
  3368.      * define       "]d"  "[d"   "]D"  "[D" "]^D"  "[^D"
  3369.      */
  3370.     if (vim_strchr((char_u *)"iI11dD04", cap->nchar) != NULL)
  3371.     {
  3372. char_u *ptr;
  3373. int len;
  3374. if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
  3375.     clearop(cap->oap);
  3376. else
  3377. {
  3378.     find_pattern_in_path(ptr, 0, len, TRUE,
  3379. cap->count0 == 0 ? !isupper(cap->nchar) : FALSE,
  3380. ((cap->nchar & 0xf) == ('d' & 0xf)) ?  FIND_DEFINE : FIND_ANY,
  3381. cap->count1,
  3382. isupper(cap->nchar) ? ACTION_SHOW_ALL :
  3383.     islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO,
  3384. cap->cmdchar == ']' ? curwin->w_cursor.lnum : (linenr_t)1,
  3385. (linenr_t)MAXLNUM);
  3386.     curwin->w_set_curswant = TRUE;
  3387. }
  3388.     }
  3389.     else
  3390. #endif
  3391.     /*
  3392.      * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
  3393.      * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
  3394.      * "[/", "[*", "]/", "]*": go to Nth comment start/end.
  3395.      */
  3396.     if (  (cap->cmdchar == '['
  3397. && vim_strchr((char_u *)"{(*/#", cap->nchar) != NULL)
  3398.     || (cap->cmdchar == ']'
  3399. && vim_strchr((char_u *)"})*/#", cap->nchar) != NULL))
  3400.     {
  3401. if (cap->nchar == '*')
  3402.     cap->nchar = '/';
  3403. new_pos.lnum = 0;
  3404. for (n = cap->count1; n > 0; --n)
  3405. {
  3406.     if ((pos = findmatchlimit(cap->oap, cap->nchar,
  3407. (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
  3408.     {
  3409. if (new_pos.lnum == 0) /* nothing found */
  3410.     clearopbeep(cap->oap);
  3411. else
  3412.     pos = &new_pos; /* use last one found */
  3413. break;
  3414.     }
  3415.     curwin->w_cursor = *pos;
  3416.     new_pos = *pos;
  3417. }
  3418. curwin->w_cursor = old_pos;
  3419. if (pos != NULL)
  3420. {
  3421.     setpcmark();
  3422.     curwin->w_cursor = *pos;
  3423.     curwin->w_set_curswant = TRUE;
  3424. }
  3425.     }
  3426.     /*
  3427.      * "[[", "[]", "]]" and "][": move to start or end of function
  3428.      */
  3429.     else if (cap->nchar == '[' || cap->nchar == ']')
  3430.     {
  3431. if (cap->nchar == cap->cmdchar)     /* "]]" or "[[" */
  3432.     flag = '{';
  3433. else
  3434.     flag = '}';     /* "][" or "[]" */
  3435. curwin->w_set_curswant = TRUE;
  3436. /*
  3437.  * Imitate strange Vi behaviour: When using "]]" with an operator
  3438.  * we also stop at '}'.
  3439.  */
  3440. if (!findpar(cap->oap, dir, cap->count1, flag,
  3441.       (cap->oap->op_type != OP_NOP && dir == FORWARD && flag == '{')))
  3442.     clearopbeep(cap->oap);
  3443. else if (cap->oap->op_type == OP_NOP)
  3444.     beginline(BL_WHITE | BL_FIX);
  3445.     }
  3446.     /*
  3447.      * "[p", "[P", "]P" and "]p": put with indent adjustment
  3448.      */
  3449.     else if (cap->nchar == 'p' || cap->nchar == 'P')
  3450.     {
  3451. if (!checkclearopq(cap->oap))
  3452. {
  3453.     prep_redo_cmd(cap);
  3454.     do_put(cap->oap->regname,
  3455.       (cap->cmdchar == ']' && cap->nchar == 'p') ? FORWARD : BACKWARD,
  3456.   cap->count1, PUT_FIXINDENT);
  3457. }
  3458.     }
  3459. #ifdef USE_MOUSE
  3460.     /*
  3461.      * [ or ] followed by a middle mouse click: put selected text with
  3462.      * indent adjustment.  Any other button just does as usual.
  3463.      */
  3464.     else if (cap->nchar >= K_LEFTMOUSE && cap->nchar <= K_RIGHTRELEASE)
  3465.     {
  3466. (void)do_mouse(cap->oap, cap->nchar,
  3467.        (cap->cmdchar == ']') ? FORWARD : BACKWARD,
  3468.        cap->count1, PUT_FIXINDENT);
  3469.     }
  3470. #endif /* USE_MOUSE */
  3471.     /* Not a valid cap->nchar. */
  3472.     else
  3473. clearopbeep(cap->oap);
  3474. }
  3475. /*
  3476.  * Handle Normal mode "%" command.
  3477.  */
  3478.     static void
  3479. nv_percent(cap)
  3480.     CMDARG *cap;
  3481. {
  3482.     FPOS *pos;
  3483.     cap->oap->inclusive = TRUE;
  3484.     if (cap->count0)     /* {cnt}% : goto {cnt} percentage in file */
  3485.     {
  3486. if (cap->count0 > 100)
  3487.     clearopbeep(cap->oap);
  3488. else
  3489. {
  3490.     cap->oap->motion_type = MLINE;
  3491.     setpcmark();
  3492.     /* round up, so CTRL-G will give same value */
  3493.     curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
  3494.       cap->count0 + 99) / 100;
  3495.     beginline(BL_SOL | BL_FIX);
  3496. }
  3497.     }
  3498.     else     /* "%" : go to matching paren */
  3499.     {
  3500. cap->oap->motion_type = MCHAR;
  3501. if ((pos = findmatch(cap->oap, NUL)) == NULL)
  3502.     clearopbeep(cap->oap);
  3503. else
  3504. {
  3505.     setpcmark();
  3506.     curwin->w_cursor = *pos;
  3507.     curwin->w_set_curswant = TRUE;
  3508.     adjust_for_sel(cap);
  3509. }
  3510.     }
  3511. }
  3512. /*
  3513.  * Handle "(" and ")" commands.
  3514.  */
  3515.     static void
  3516. nv_brace(cap, dir)
  3517.     CMDARG *cap;
  3518.     int dir;
  3519. {
  3520.     cap->oap->motion_type = MCHAR;
  3521.     if (cap->cmdchar == ')')
  3522. cap->oap->inclusive = FALSE;
  3523.     else
  3524. cap->oap->inclusive = TRUE;
  3525.     curwin->w_set_curswant = TRUE;
  3526.     if (findsent(dir, cap->count1) == FAIL)
  3527. clearopbeep(cap->oap);
  3528. }
  3529. /*
  3530.  * Handle the "r" command.
  3531.  */
  3532.     static int
  3533. n_replace(cap)
  3534.     CMDARG *cap;
  3535. {
  3536.     char_u *ptr;
  3537.     int had_ctrl_v;
  3538.     int command_busy = FALSE;
  3539.     long n;
  3540.     ptr = ml_get_cursor();
  3541.     /* special key or not enough characters to replace */
  3542. #ifdef MULTI_BYTE
  3543.     if (
  3544. /* SB case: */
  3545. (!is_dbcs
  3546.      && ((cap->nchar >= 0x100 || STRLEN(ptr) < (unsigned)cap->count1)))
  3547. /* DBCS case: */
  3548. || (is_dbcs && ((cap->nchar >= 0x100
  3549.     /* does not support multi-replacement for multi-byte */
  3550.     || (IsLeadByte(cap->nchar) && cap->count1 > 1)
  3551.     || ((MultiStrLen(ptr) < cap->count1)
  3552. /* support single-replacement for multi-byte */
  3553. && !(STRLEN(ptr) >= 2 && (unsigned)cap->count1 == 1))))))
  3554. #else
  3555. if (cap->nchar >= 0x100 || STRLEN(ptr) < (unsigned)cap->count1)
  3556. #endif
  3557.     {
  3558. clearopbeep(cap->oap);
  3559. return FALSE;
  3560.     }
  3561.     /*
  3562.      * Replacing with a TAB is done by edit(), because it is complicated when
  3563.      * 'expandtab', 'smarttab' or 'softtabstop' is set.
  3564.      * Other characters are done below to avoid problems with things like
  3565.      * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
  3566.      */
  3567.     if (cap->nchar == 't' && (curbuf->b_p_et || p_sta))
  3568.     {
  3569. stuffnumReadbuff(cap->count1);
  3570. stuffcharReadbuff('R');
  3571. stuffcharReadbuff('t');
  3572. stuffcharReadbuff(ESC);
  3573. return FALSE;
  3574.     }
  3575.     if (cap->nchar == Ctrl('V')) /* get another character */
  3576.     {
  3577. had_ctrl_v = Ctrl('V');
  3578. cap->nchar = get_literal();
  3579.     }
  3580.     else
  3581. had_ctrl_v = NUL;
  3582.     if (u_save_cursor() == FAIL) /* save line for undo */
  3583. return FALSE;
  3584.     if (had_ctrl_v != Ctrl('V') && (cap->nchar == 'r' || cap->nchar == 'n'))
  3585.     {
  3586. /*
  3587.  * Replace character(s) by a single newline.
  3588.  * Strange vi behaviour: Only one newline is inserted.
  3589.  * Delete the characters here.
  3590.  * Insert the newline with an insert command, takes care of
  3591.  * autoindent. The insert command depends on being on the last
  3592.  * character of a line or not.
  3593.  */
  3594. (void)del_chars(cap->count1, FALSE); /* delete the characters */
  3595. stuffcharReadbuff('r');
  3596. stuffcharReadbuff(ESC);
  3597. /*
  3598.  * Give 'r' to edit(), to get the redo command right.
  3599.  */
  3600. command_busy = edit('r', FALSE, cap->count1);
  3601.     }
  3602.     else
  3603.     {
  3604. #ifdef MULTI_BYTE
  3605. int trailbyte = NUL;
  3606. int prechar = NUL; /* init for GCC */
  3607. if (is_dbcs && IsLeadByte(cap->nchar))
  3608.     trailbyte = (char_u)vgetc();
  3609. #endif
  3610. prep_redo(cap->oap->regname, cap->count1,
  3611.     NUL, 'r', had_ctrl_v, cap->nchar);
  3612. for (n = cap->count1; n > 0; --n) /* replace the characters */
  3613. {
  3614.     /*
  3615.      * Replace a 'normal' character.
  3616.      * Get ptr again, because u_save and/or showmatch() will have
  3617.      * released the line.  At the same time we let know that the line
  3618.      * will be changed.
  3619.      */
  3620.     ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
  3621. #ifdef MULTI_BYTE
  3622.     if (is_dbcs)
  3623. prechar = ptr[curwin->w_cursor.col];
  3624. #endif
  3625.     ptr[curwin->w_cursor.col] = cap->nchar;
  3626.     if (       p_sm
  3627.     && (cap->nchar == ')'
  3628. || cap->nchar == '}'
  3629. || cap->nchar == ']'))
  3630. showmatch();
  3631.     ++curwin->w_cursor.col;
  3632. #ifdef MULTI_BYTE
  3633.     if (is_dbcs)
  3634.     {
  3635. if (trailbyte != NUL)
  3636.     ptr[curwin->w_cursor.col++] = trailbyte;
  3637. else if (IsLeadByte(prechar))
  3638.     (void)del_chars((long)1, TRUE);
  3639.     }
  3640. #endif
  3641. }
  3642. --curwin->w_cursor.col;     /* cursor on the last replaced char */
  3643. curwin->w_set_curswant = TRUE;
  3644. set_last_insert(cap->nchar);
  3645. changed_cline_bef_curs();   /* update cursor screen pos. later */
  3646. /* w_botline might change a bit when replacing special characters */
  3647. approximate_botline();
  3648. update_screenline();
  3649.     }
  3650.     changed();
  3651.     return command_busy;
  3652. }
  3653. /*
  3654.  * 'o': Exchange start and end of Visual area.
  3655.  * 'O': same, but in block mode exchange left and right corners.
  3656.  */
  3657.     static void
  3658. v_swap_corners(cap)
  3659.     CMDARG *cap;
  3660. {
  3661.     FPOS old_cursor;
  3662.     colnr_t left, right;
  3663.     if ((cap->cmdchar == 'O') && VIsual_mode == Ctrl('V'))
  3664.     {
  3665. old_cursor = curwin->w_cursor;
  3666. getvcols(&old_cursor, &VIsual, &left, &right);
  3667. curwin->w_cursor.lnum = VIsual.lnum;
  3668. coladvance(left);
  3669. VIsual = curwin->w_cursor;
  3670. curwin->w_cursor.lnum = old_cursor.lnum;
  3671. coladvance(right);
  3672. curwin->w_curswant = right;
  3673. if (curwin->w_cursor.col == old_cursor.col)
  3674. {
  3675.     curwin->w_cursor.lnum = VIsual.lnum;
  3676.     coladvance(right);
  3677.     VIsual = curwin->w_cursor;
  3678.     curwin->w_cursor.lnum = old_cursor.lnum;
  3679.     coladvance(left);
  3680.     curwin->w_curswant = left;
  3681. }
  3682.     }
  3683.     if (cap->cmdchar != 'O' || VIsual_mode != Ctrl('V'))
  3684.     {
  3685. old_cursor = curwin->w_cursor;
  3686. curwin->w_cursor = VIsual;
  3687. VIsual = old_cursor;
  3688. curwin->w_set_curswant = TRUE;
  3689.     }
  3690. }
  3691. /*
  3692.  * "R".
  3693.  */
  3694.     static int
  3695. nv_replace(cap)
  3696.     CMDARG     *cap;
  3697. {
  3698.     int     command_busy = FALSE;
  3699.     if (VIsual_active) /* "R" is replace lines */
  3700.     {
  3701. cap->cmdchar = 'c';
  3702. VIsual_mode = 'V';
  3703. nv_operator(cap);
  3704.     }
  3705.     else if (!checkclearopq(cap->oap))
  3706.     {
  3707. if (u_save_cursor() == OK)
  3708.     command_busy = edit('R', FALSE, cap->count1);
  3709.     }
  3710.     return command_busy;
  3711. }
  3712. /*
  3713.  * Swap case for "~" command, when it does not work like an operator.
  3714.  */
  3715.     static void
  3716. n_swapchar(cap)
  3717.     CMDARG *cap;
  3718. {
  3719.     long n;
  3720.     if (checkclearopq(cap->oap))
  3721. return;
  3722.     if (lineempty(curwin->w_cursor.lnum))
  3723.     {
  3724. clearopbeep(cap->oap);
  3725. return;
  3726.     }
  3727.     prep_redo_cmd(cap);
  3728.     if (u_save_cursor() == FAIL)
  3729. return;
  3730.     for (n = cap->count1; n > 0; --n)
  3731.     {
  3732. if (gchar_cursor() == NUL)
  3733.     break;
  3734. swapchar(cap->oap->op_type, &curwin->w_cursor);
  3735. inc_cursor();
  3736.     }
  3737.     adjust_cursor();
  3738.     curwin->w_set_curswant = TRUE;
  3739.     changed();
  3740.     /* assume that the length of the line doesn't change, so w_botline
  3741.      * remains valid */
  3742.     update_screenline();
  3743. }
  3744. /*
  3745.  * Move cursor to mark.
  3746.  */
  3747.     static void
  3748. nv_cursormark(cap, flag, pos)
  3749.     CMDARG *cap;
  3750.     int flag;
  3751.     FPOS *pos;
  3752. {
  3753.     if (check_mark(pos) == FAIL)
  3754. clearop(cap->oap);
  3755.     else
  3756.     {
  3757. if (cap->cmdchar == ''' || cap->cmdchar == '`')
  3758.     setpcmark();
  3759. curwin->w_cursor = *pos;
  3760. if (flag)
  3761.     beginline(BL_WHITE | BL_FIX);
  3762. else
  3763.     adjust_cursor();
  3764.     }
  3765.     cap->oap->motion_type = flag ? MLINE : MCHAR;
  3766.     cap->oap->inclusive = FALSE; /* ignored if not MCHAR */
  3767.     curwin->w_set_curswant = TRUE;
  3768. }
  3769. /*
  3770.  * Handle commands that are operators in Visual mode.
  3771.  */
  3772.     static void
  3773. v_visop(cap)
  3774.     CMDARG *cap;
  3775. {
  3776.     static char_u trans[] = "YyDdCcxdXd";
  3777.     /* Uppercase means linewise, except in block mode, then "D" deletes till
  3778.      * the end of the line. */
  3779.     if (isupper(cap->cmdchar))
  3780.     {
  3781. if (VIsual_mode != Ctrl('V'))
  3782.     VIsual_mode = 'V';
  3783. else if (cap->cmdchar == 'D')
  3784.     curwin->w_curswant = MAXCOL;
  3785.     }
  3786.     cap->cmdchar = *(vim_strchr(trans, cap->cmdchar) + 1);
  3787.     nv_operator(cap);
  3788. }
  3789. /*
  3790.  * Translate a command into another command.
  3791.  */
  3792.     static void
  3793. nv_optrans(cap)
  3794.     CMDARG *cap;
  3795. {
  3796.     static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
  3797.       (char_u *)"d$", (char_u *)"c$",
  3798.       (char_u *)"cl", (char_u *)"cc",
  3799.       (char_u *)"yy", (char_u *)":sr"};
  3800.     static char_u *str = (char_u *)"xXDCsSY&";
  3801.     if (!checkclearopq(cap->oap))
  3802.     {
  3803. if (cap->count0)
  3804.     stuffnumReadbuff(cap->count0);
  3805. stuffReadbuff(ar[(int)(vim_strchr(str, cap->cmdchar) - str)]);
  3806.     }
  3807. }
  3808. /*
  3809.  * Handle "'" and "`" commands.
  3810.  */
  3811.     static void
  3812. nv_gomark(cap, flag)
  3813.     CMDARG *cap;
  3814.     int flag;
  3815. {
  3816.     FPOS *pos;
  3817.     pos = getmark(cap->nchar, (cap->oap->op_type == OP_NOP));
  3818.     if (pos == (FPOS *)-1)     /* jumped to other file */
  3819.     {
  3820. if (flag)
  3821.     beginline(BL_WHITE | BL_FIX);
  3822. else
  3823.     adjust_cursor();
  3824.     }
  3825.     else
  3826. nv_cursormark(cap, flag, pos);
  3827. }
  3828. /*
  3829.  * Handle CTRL-O and CTRL-I commands.
  3830.  */
  3831.     static void
  3832. nv_pcmark(cap)
  3833.     CMDARG *cap;
  3834. {
  3835.     FPOS *pos;
  3836.     if (!checkclearopq(cap->oap))
  3837.     {
  3838. pos = movemark((int)cap->count1);
  3839. if (pos == (FPOS *)-1) /* jump to other file */
  3840. {
  3841.     curwin->w_set_curswant = TRUE;
  3842.     adjust_cursor();
  3843. }
  3844. else if (pos != NULL)     /* can jump */
  3845.     nv_cursormark(cap, FALSE, pos);
  3846. else
  3847.     clearopbeep(cap->oap);
  3848.     }
  3849. }
  3850. /*
  3851.  * Handle '"' command.
  3852.  */
  3853.     static void
  3854. nv_regname(cap, opnump)
  3855.     CMDARG *cap;
  3856.     linenr_t *opnump;
  3857. {
  3858.     if (checkclearop(cap->oap))
  3859. return;
  3860. #ifdef WANT_EVAL
  3861.     if (cap->nchar == '=')
  3862. cap->nchar = get_expr_register();
  3863. #endif
  3864.     if (cap->nchar != NUL && valid_yank_reg(cap->nchar, FALSE))
  3865.     {
  3866. cap->oap->regname = cap->nchar;
  3867. *opnump = cap->count0;     /* remember count before '"' */
  3868.     }
  3869.     else
  3870. clearopbeep(cap->oap);
  3871. }
  3872. /*
  3873.  * Handle "v", "V" and "CTRL-V" commands.
  3874.  * Also for "gh", "gH" and "g^H" commands.
  3875.  */
  3876.     static void
  3877. nv_visual(cap, selectmode)
  3878.     CMDARG *cap;
  3879.     int selectmode;     /* Always start selectmode */
  3880. {
  3881.     VIsual_select = selectmode;
  3882.     if (VIsual_active)     /* change Visual mode */
  3883.     {
  3884. if (VIsual_mode == cap->cmdchar)    /* stop visual mode */
  3885.     end_visual_mode();
  3886. else     /* toggle char/block mode */
  3887. {     /*    or char/line mode */
  3888.     VIsual_mode = cap->cmdchar;
  3889.     showmode();
  3890. }
  3891. update_curbuf(NOT_VALID);     /* update the inversion */
  3892.     }
  3893.     else     /* start Visual mode */
  3894.     {
  3895. check_visual_highlight();
  3896. if (cap->count0)     /* use previously selected part */
  3897. {
  3898.     if (resel_VIsual_mode == NUL)   /* there is none */
  3899.     {
  3900. beep_flush();
  3901. return;
  3902.     }
  3903.     VIsual = curwin->w_cursor;
  3904.     VIsual_active = TRUE;
  3905.     VIsual_reselect = TRUE;
  3906.     if (!selectmode)
  3907. /* start Select mode when 'selectmode' contains "cmd" */
  3908. may_start_select('c');
  3909. #ifdef USE_MOUSE
  3910.     setmouse();
  3911. #endif
  3912.     if (p_smd)
  3913. redraw_cmdline = TRUE;     /* show visual mode later */
  3914.     /*
  3915.      * For V and ^V, we multiply the number of lines even if there
  3916.      * was only one -- webb
  3917.      */
  3918.     if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
  3919.     {
  3920. curwin->w_cursor.lnum +=
  3921.     resel_VIsual_line_count * cap->count0 - 1;
  3922. if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3923.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  3924.     }
  3925.     VIsual_mode = resel_VIsual_mode;
  3926.     if (VIsual_mode == 'v')
  3927.     {
  3928. if (resel_VIsual_line_count <= 1)
  3929.     curwin->w_cursor.col += resel_VIsual_col * cap->count0 - 1;
  3930. else
  3931.     curwin->w_cursor.col = resel_VIsual_col;
  3932.     }
  3933.     if (resel_VIsual_col == MAXCOL)
  3934.     {
  3935. curwin->w_curswant = MAXCOL;
  3936. coladvance(MAXCOL);
  3937.     }
  3938.     else if (VIsual_mode == Ctrl('V'))
  3939.     {
  3940. validate_virtcol();
  3941. curwin->w_curswant = curwin->w_virtcol +
  3942.    resel_VIsual_col * cap->count0 - 1;
  3943. coladvance(curwin->w_curswant);
  3944.     }
  3945.     else
  3946. curwin->w_set_curswant = TRUE;
  3947.     update_curbuf(NOT_VALID); /* show the inversion */
  3948. }
  3949. else
  3950. {
  3951.     if (!selectmode)
  3952. /* start Select mode when 'selectmode' contains "cmd" */
  3953. may_start_select('c');
  3954.     n_start_visual_mode(cap->cmdchar);
  3955. }
  3956.     }
  3957. }
  3958. /*
  3959.  * Start selection for Shift-movement keys.
  3960.  */
  3961.     void
  3962. start_selection()
  3963. {
  3964.     /* if 'selectmode' contains "key", start Select mode */
  3965.     may_start_select('k');
  3966.     n_start_visual_mode('v');
  3967. }
  3968. /*
  3969.  * Start Select mode, if "c" is in 'selectmode' and not in a mapping or menu.
  3970.  */
  3971.     void
  3972. may_start_select(c)
  3973.     int c;
  3974. {
  3975.     VIsual_select = (stuff_empty() && typebuf_typed()
  3976.     && (vim_strchr(p_slm, c) != NULL));
  3977. }
  3978. /*
  3979.  * Start Visual mode "c".
  3980.  * Should set VIsual_select before calling this.
  3981.  */
  3982.     static void
  3983. n_start_visual_mode(c)
  3984.     int c;
  3985. {
  3986.     VIsual = curwin->w_cursor;
  3987.     VIsual_mode = c;
  3988.     VIsual_active = TRUE;
  3989.     VIsual_reselect = TRUE;
  3990. #ifdef USE_MOUSE
  3991.     setmouse();
  3992. #endif
  3993.     if (p_smd)
  3994. redraw_cmdline = TRUE; /* show visual mode later */
  3995.     update_screenline(); /* start the inversion */
  3996. }
  3997. /*
  3998.  * Handle the "g" command.
  3999.  */
  4000.     static int
  4001. nv_g_cmd(cap, searchp)
  4002.     CMDARG *cap;
  4003.     char_u **searchp;
  4004. {
  4005.     OPARG *oap = cap->oap;
  4006.     FPOS tpos;
  4007.     int i;
  4008.     int flag = FALSE;
  4009.     int command_busy = FALSE;
  4010.     switch (cap->nchar)
  4011.     {
  4012. #ifdef MEM_PROFILE
  4013.     /*
  4014.      * "g^A": dump log of used memory.
  4015.      */
  4016.     case Ctrl('A'):
  4017. vim_mem_profile_dump();
  4018. break;
  4019. #endif
  4020.     /*
  4021.      * "gv": Reselect the previous Visual area.  If Visual already active,
  4022.      *      exchange previous and current Visual area.
  4023.      */
  4024.     case 'v':
  4025. if (checkclearop(oap))
  4026.     break;
  4027. if (    curbuf->b_visual_start.lnum == 0
  4028. || curbuf->b_visual_start.lnum > curbuf->b_ml.ml_line_count
  4029. || curbuf->b_visual_end.lnum == 0)
  4030.     beep_flush();
  4031. else
  4032. {
  4033.     if (VIsual_active)
  4034.     {
  4035. tpos = VIsual;
  4036. VIsual = curbuf->b_visual_start;
  4037. curbuf->b_visual_start = tpos;
  4038. i = VIsual_mode;
  4039. VIsual_mode = curbuf->b_visual_mode;
  4040. curbuf->b_visual_mode = i;
  4041. tpos = curwin->w_cursor;
  4042. curwin->w_cursor = curbuf->b_visual_end;
  4043. curbuf->b_visual_end = tpos;
  4044.     }
  4045.     else
  4046.     {
  4047. VIsual = curbuf->b_visual_start;
  4048. curwin->w_cursor = curbuf->b_visual_end;
  4049. VIsual_mode = curbuf->b_visual_mode;
  4050.     }
  4051.     VIsual_active = TRUE;
  4052.     VIsual_reselect = TRUE;
  4053.     check_cursor_lnum();
  4054.     update_topline();
  4055.     /*
  4056.      * When called from normal "g" command: start Select mode when
  4057.      * 'selectmode' contains "cmd".  When called for K_SELECT, always
  4058.      * start Select mode
  4059.      */
  4060.     if (searchp == NULL)
  4061. VIsual_select = TRUE;
  4062.     else
  4063. may_start_select('c');
  4064. #ifdef USE_MOUSE
  4065.     setmouse();
  4066. #endif
  4067.     update_curbuf(NOT_VALID);
  4068.     showmode();
  4069. }
  4070. break;
  4071.     /*
  4072.      * "gV": Don't reselect the previous Visual area after a Select mode
  4073.      *      mapping of menu.
  4074.      */
  4075.     case 'V':
  4076. VIsual_reselect = FALSE;
  4077. break;
  4078.     /*
  4079.      * "gh":  start Select mode.
  4080.      * "gH":  start Select line mode.
  4081.      * "g^H": start Select block mode.
  4082.      */
  4083.     case K_BS:
  4084. cap->nchar = Ctrl('H');
  4085. /* FALLTHROUGH */
  4086.     case 'h':
  4087.     case 'H':
  4088.     case Ctrl('H'):
  4089. if (!checkclearop(oap))
  4090. {
  4091.     cap->cmdchar = cap->nchar + ('v' - 'h');
  4092.     nv_visual(cap, TRUE);
  4093. }
  4094. break;
  4095.     /*
  4096.      * "gj" and "gk" two new funny movement keys -- up and down
  4097.      * movement based on *screen* line rather than *file* line.
  4098.      */
  4099.     case 'j':
  4100.     case K_DOWN:
  4101. /* with 'nowrap' it works just like the normal "j" command */
  4102. if (!curwin->w_p_wrap)
  4103. {
  4104.     oap->motion_type = MLINE;
  4105.     i = cursor_down(cap->count1, oap->op_type == OP_NOP);
  4106. }
  4107. else
  4108.     i = nv_screengo(oap, FORWARD, cap->count1);
  4109. if (i == FAIL)
  4110.     clearopbeep(oap);
  4111. break;
  4112.     case 'k':
  4113.     case K_UP:
  4114. /* with 'nowrap' it works just like the normal "k" command */
  4115. if (!curwin->w_p_wrap)
  4116. {
  4117.     oap->motion_type = MLINE;
  4118.     i = cursor_up(cap->count1, oap->op_type == OP_NOP);
  4119. }
  4120. else
  4121.     i = nv_screengo(oap, BACKWARD, cap->count1);
  4122. if (i == FAIL)
  4123.     clearopbeep(oap);
  4124. break;
  4125.     /*
  4126.      * "gJ": join two lines without inserting a space.
  4127.      */
  4128.     case 'J':
  4129. oap->op_prechar = 'g';
  4130. cap->cmdchar = 'J';
  4131. nv_join(cap);
  4132. break;
  4133.     /*
  4134.      * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
  4135.      */
  4136.     case '^':
  4137. flag = TRUE;
  4138. /* FALLTHROUGH */
  4139.     case '0':
  4140.     case K_HOME:
  4141.     case K_KHOME:
  4142. oap->motion_type = MCHAR;
  4143. oap->inclusive = FALSE;
  4144. if (curwin->w_p_wrap)
  4145. {
  4146.     validate_virtcol();
  4147.     i = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  4148.    Columns) * Columns;
  4149.     if (curwin->w_p_nu && i > 8)
  4150. i -= 8;
  4151. }
  4152. else
  4153.     i = curwin->w_leftcol;
  4154. coladvance((colnr_t)i);
  4155. if (flag)
  4156. {
  4157.     do
  4158. i = gchar_cursor();
  4159.     while (vim_iswhite(i) && oneright() == OK);
  4160. }
  4161. curwin->w_set_curswant = TRUE;
  4162. break;
  4163.     case '$':
  4164.     case K_END:
  4165.     case K_KEND:
  4166. oap->motion_type = MCHAR;
  4167. oap->inclusive = TRUE;
  4168. if (curwin->w_p_wrap)
  4169. {
  4170.     curwin->w_curswant = MAXCOL;    /* so we stay at the end */
  4171.     if (cap->count1 == 1)
  4172.     {
  4173. validate_virtcol();
  4174. i = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  4175.    Columns + 1) * Columns - 1;
  4176. if (curwin->w_p_nu && i > 8)
  4177.     i -= 8;
  4178. coladvance((colnr_t)i);
  4179.     }
  4180.     else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == FAIL)
  4181. clearopbeep(oap);
  4182. }
  4183. else
  4184. {
  4185.     i = curwin->w_leftcol + Columns - 1;
  4186.     if (curwin->w_p_nu)
  4187. i -= 8;
  4188.     coladvance((colnr_t)i);
  4189.     curwin->w_set_curswant = TRUE;
  4190. }
  4191. break;
  4192.     /*
  4193.      * "g*" and "g#", like "*" and "#" but without using "<" and ">"
  4194.      */
  4195.     case '*':
  4196.     case '#':
  4197. nv_ident(cap, searchp);
  4198. break;
  4199.     /*
  4200.      * ge and gE: go back to end of word
  4201.      */
  4202.     case 'e':
  4203.     case 'E':
  4204. oap->motion_type = MCHAR;
  4205. curwin->w_set_curswant = TRUE;
  4206. oap->inclusive = TRUE;
  4207. if (bckend_word(cap->count1, cap->nchar == 'E', FALSE) == FAIL)
  4208.     clearopbeep(oap);
  4209. break;
  4210.     /*
  4211.      * "g CTRL-G": display info about cursor position
  4212.      */
  4213.     case Ctrl('G'):
  4214. cursor_pos_info();
  4215. break;
  4216.     /*
  4217.      * "gI": Start insert in column 1.
  4218.      */
  4219.     case 'I':
  4220. beginline(0);
  4221. if (!checkclearopq(oap))
  4222. {
  4223.     if (u_save_cursor() == OK)
  4224. command_busy = edit('g', FALSE, cap->count1);
  4225. }
  4226. break;
  4227. #ifdef FILE_IN_PATH
  4228.     /*
  4229.      * "gf": goto file, edit file under cursor
  4230.      * "]f" and "[f": can also be used.
  4231.      */
  4232.     case 'f':
  4233. nv_gotofile(cap);
  4234. break;
  4235. #endif
  4236.     /*
  4237.      * "gs": Goto sleep, but keep on checking for CTRL-C
  4238.      */
  4239.     case 's':
  4240. out_flush();
  4241. while (cap->count1-- && !got_int)
  4242. {
  4243.     ui_delay(1000L, TRUE);
  4244.     ui_breakcheck();
  4245. }
  4246. break;
  4247.     /*
  4248.      * "ga": Display the ascii value of the character under the
  4249.      * cursor. It is displayed in decimal, hex, and octal. -- webb
  4250.      */
  4251.     case 'a':
  4252. do_ascii();
  4253. break;
  4254.     /*
  4255.      * "gg": Goto the first line in file.  With a count it goes to
  4256.      * that line number like for "G". -- webb
  4257.      */
  4258.     case 'g':
  4259. nv_goto(oap, cap->count0); /* nv_goto() will change 0 into 1 */
  4260. break;
  4261.     /*
  4262.      *  Two-character operators:
  4263.      *  "gq"     Format text
  4264.      *  "g~"     Toggle the case of the text.
  4265.      *  "gu"     Change text to lower case.
  4266.      *  "gU"     Change text to upper case.
  4267.      */
  4268.     case 'q':
  4269.     case '~':
  4270.     case 'u':
  4271.     case 'U':
  4272. oap->op_prechar = 'g';
  4273. cap->cmdchar = cap->nchar;
  4274. nv_operator(cap);
  4275. break;
  4276. /*
  4277.  * "gd": Find first occurence of pattern under the cursor in the
  4278.  *  current function
  4279.  * "gD": idem, but in the current file.
  4280.  */
  4281.     case 'd':
  4282.     case 'D':
  4283. nv_gd(oap, cap->nchar);
  4284. break;
  4285. #ifdef USE_MOUSE
  4286.     /*
  4287.      * g<*Mouse> : <C-*mouse>
  4288.      */
  4289.     case K_MIDDLEMOUSE:
  4290.     case K_MIDDLEDRAG:
  4291.     case K_MIDDLERELEASE:
  4292.     case K_LEFTMOUSE:
  4293.     case K_LEFTDRAG:
  4294.     case K_LEFTRELEASE:
  4295.     case K_RIGHTMOUSE:
  4296.     case K_RIGHTDRAG:
  4297.     case K_RIGHTRELEASE:
  4298. mod_mask = MOD_MASK_CTRL;
  4299. (void)do_mouse(oap, cap->nchar, BACKWARD, cap->count1, 0);
  4300. break;
  4301.     case K_IGNORE:
  4302. break;
  4303. #endif
  4304.     case Ctrl(']'): /* :tag or :tselect for current identifier */
  4305.     case ']': /* :tselect for current identifier */
  4306. nv_ident(cap, searchp);
  4307. break;
  4308.     /*
  4309.      * "gP" and "gp": same as "P" and "p" but leave cursor just after new text
  4310.      */
  4311.     case 'p':
  4312.     case 'P':
  4313. nv_put(cap);
  4314. break;
  4315.     default:
  4316. clearopbeep(oap);
  4317. break;
  4318.     }
  4319.     return command_busy;
  4320. }
  4321. /*
  4322.  * Handle "o" and "O" commands.
  4323.  */
  4324.     static int
  4325. n_opencmd(cap)
  4326.     CMDARG *cap;
  4327. {
  4328.     int     command_busy = FALSE;
  4329.     if (!checkclearopq(cap->oap))
  4330.     {
  4331. if (has_format_option(FO_OPEN_COMS))
  4332.     fo_do_comments = TRUE;
  4333. if (u_save((linenr_t)(curwin->w_cursor.lnum -
  4334.        (cap->cmdchar == 'O' ? 1 : 0)),
  4335.    (linenr_t)(curwin->w_cursor.lnum +
  4336.        (cap->cmdchar == 'o' ? 1 : 0))
  4337.        ) == OK
  4338. && open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
  4339.   TRUE, FALSE, 0))
  4340.     command_busy = edit(cap->cmdchar, TRUE, cap->count1);
  4341. fo_do_comments = FALSE;
  4342.     }
  4343.     return command_busy;
  4344. }
  4345. /*
  4346.  * Handle "U" command.
  4347.  */
  4348.     static void
  4349. nv_Undo(cap)
  4350.     CMDARG *cap;
  4351. {
  4352.     /* In visual mode and typing "gUU" triggers an operator */
  4353.     if (VIsual_active || cap->oap->op_type == OP_UPPER)
  4354.     {
  4355. nv_operator(cap);
  4356.     }
  4357.     else if (!checkclearopq(cap->oap))
  4358.     {
  4359. u_undoline();
  4360. curwin->w_set_curswant = TRUE;
  4361.     }
  4362. }
  4363. /*
  4364.  * Handle an operator command.
  4365.  */
  4366.     static void
  4367. nv_operator(cap)
  4368.     CMDARG *cap;
  4369. {
  4370.     int     i;
  4371.     i = vim_strchr(op_chars, cap->cmdchar) - op_chars + 1;
  4372.     if (i == cap->oap->op_type)     /* double operator works on lines */
  4373.     {
  4374. /* Redo for "gqgq" should be done with prechar = 'g', cmdchar = 'q',
  4375.  * nchar = 'q'; same for "gugu", "gUgU" and "g~g~".  But don't do this
  4376.  * for "gqq", "g~~", "guu" and "gUU". */
  4377. if (cap->nchar && (cap->oap->op_type == OP_FORMAT
  4378.     || cap->oap->op_type == OP_UPPER
  4379.     || cap->oap->op_type == OP_LOWER
  4380.     || cap->oap->op_type == OP_TILDE))
  4381.     cap->cmdchar = 'g';
  4382. nv_lineop(cap);
  4383.     }
  4384.     else if (!checkclearop(cap->oap))
  4385.     {
  4386. cap->oap->start = curwin->w_cursor;
  4387. cap->oap->op_type = i;
  4388.     }
  4389. }
  4390. /*
  4391.  * Handle linewise operator "dd", "yy", etc.
  4392.  */
  4393.     static void
  4394. nv_lineop(cap)
  4395.     CMDARG *cap;
  4396. {
  4397.     cap->oap->motion_type = MLINE;
  4398.     if (cursor_down(cap->count1 - 1L, cap->oap->op_type == OP_NOP) == FAIL)
  4399. clearopbeep(cap->oap);
  4400.     else if (  cap->oap->op_type == OP_DELETE
  4401.     || cap->oap->op_type == OP_LSHIFT
  4402.     || cap->oap->op_type == OP_RSHIFT)
  4403. beginline(BL_SOL | BL_FIX);
  4404.     else if (cap->oap->op_type != OP_YANK) /* 'Y' does not move cursor */
  4405. beginline(BL_WHITE | BL_FIX);
  4406. }
  4407. /*
  4408.  * Handle "|" command.
  4409.  */
  4410.     static void
  4411. nv_pipe(cap)
  4412.     CMDARG *cap;
  4413. {
  4414.     cap->oap->motion_type = MCHAR;
  4415.     cap->oap->inclusive = FALSE;
  4416.     beginline(0);
  4417.     if (cap->count0 > 0)
  4418.     {
  4419. coladvance((colnr_t)(cap->count0 - 1));
  4420. curwin->w_curswant = (colnr_t)(cap->count0 - 1);
  4421.     }
  4422.     else
  4423. curwin->w_curswant = 0;
  4424.     /* keep curswant at the column where we wanted to go, not where
  4425.        we ended; differs is line is too short */
  4426.     curwin->w_set_curswant = FALSE;
  4427. }
  4428. /*
  4429.  * Handle back-word command "b".
  4430.  */
  4431.     static void
  4432. nv_bck_word(cap, type)
  4433.     CMDARG *cap;
  4434.     int type;
  4435. {
  4436.     cap->oap->motion_type = MCHAR;
  4437.     cap->oap->inclusive = FALSE;
  4438.     curwin->w_set_curswant = TRUE;
  4439.     if (bck_word(cap->count1, type, FALSE) == FAIL)
  4440. clearopbeep(cap->oap);
  4441. }
  4442. /*
  4443.  * Handle word motion commands "e", "E", "w" and "W".
  4444.  */
  4445.     static void
  4446. nv_wordcmd(cap, type)
  4447.     CMDARG *cap;
  4448.     int type;
  4449. {
  4450.     int     n;
  4451.     int     word_end;
  4452.     int     flag = FALSE;
  4453.     /*
  4454.      * Inclusive has been set for the "E" and "e" command.
  4455.      */
  4456.     word_end = cap->oap->inclusive;
  4457.     /*
  4458.      * "cw" and "cW" are a special case.
  4459.      */
  4460.     if (!word_end && cap->oap->op_type == OP_CHANGE)
  4461.     {
  4462. n = gchar_cursor();
  4463. if (n != NUL) /* not an empty line */
  4464. {
  4465.     if (vim_iswhite(n))
  4466.     {
  4467. /*
  4468.  * Reproduce a funny Vi behaviour: "cw" on a blank only
  4469.  * changes one character, not all blanks until the start of
  4470.  * the next word.  Only do this when the 'w' flag is included
  4471.  * in 'cpoptions'.
  4472.  */
  4473. if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
  4474. {
  4475.     cap->oap->inclusive = TRUE;
  4476.     cap->oap->motion_type = MCHAR;
  4477.     return;
  4478. }
  4479.     }
  4480.     else
  4481.     {
  4482. /*
  4483.  * This is a little strange. To match what the real Vi does,
  4484.  * we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided
  4485.  * that we are not on a space or a TAB.  This seems impolite
  4486.  * at first, but it's really more what we mean when we say
  4487.  * 'cw'.
  4488.  * Another strangeness: When standing on the end of a word
  4489.  * "ce" will change until the end of the next wordt, but "cw"
  4490.  * will change only one character! This is done by setting
  4491.  * flag.
  4492.  */
  4493. cap->oap->inclusive = TRUE;
  4494. word_end = TRUE;
  4495. flag = TRUE;
  4496.     }
  4497. }
  4498.     }
  4499.     cap->oap->motion_type = MCHAR;
  4500.     curwin->w_set_curswant = TRUE;
  4501.     if (word_end)
  4502. n = end_word(cap->count1, type, flag, FALSE);
  4503.     else
  4504. n = fwd_word(cap->count1, type, cap->oap->op_type != OP_NOP);
  4505.     /* Don't leave the cursor on the NUL past a line */
  4506.     if (curwin->w_cursor.col && gchar_cursor() == NUL)
  4507.     {
  4508. --curwin->w_cursor.col;
  4509. cap->oap->inclusive = TRUE;
  4510.     }
  4511.     if (n == FAIL && cap->oap->op_type == OP_NOP)
  4512. clearopbeep(cap->oap);
  4513.     else
  4514. adjust_for_sel(cap);
  4515. }
  4516. /*
  4517.  * In exclusive Visual mode, may include the last character.
  4518.  */
  4519.     static void
  4520. adjust_for_sel(cap)
  4521.     CMDARG *cap;
  4522. {
  4523.     if (VIsual_active && cap->oap->inclusive && *p_sel == 'e'
  4524.      && gchar_cursor() != NUL)
  4525.     {
  4526. ++curwin->w_cursor.col;
  4527. cap->oap->inclusive = FALSE;
  4528.     }
  4529. }
  4530.     static void
  4531. nv_goto(oap, lnum)
  4532.     OPARG   *oap;
  4533.     long    lnum;
  4534. {
  4535.     oap->motion_type = MLINE;
  4536.     setpcmark();
  4537.     if (lnum < 1L)
  4538. lnum = 1L;
  4539.     else if (lnum > curbuf->b_ml.ml_line_count)
  4540. lnum = curbuf->b_ml.ml_line_count;
  4541.     curwin->w_cursor.lnum = lnum;
  4542.     beginline(BL_SOL | BL_FIX);
  4543. }
  4544. /*
  4545.  * SELECT key in Normal or Visual mode: end of Select mode mapping.
  4546.  */
  4547.     static void
  4548. nv_select(cap)
  4549.     CMDARG *cap;
  4550. {
  4551.     FPOS *pp;
  4552.     if (VIsual_active)
  4553. VIsual_select = TRUE;
  4554.     else if (VIsual_reselect)
  4555.     {
  4556. cap->nchar = 'v';     /* fake "gv" command */
  4557. nv_g_cmd(cap, NULL);
  4558. if (*p_sel == 'e' && VIsual_mode == 'v')
  4559. {
  4560.     /* exclusive mode: advance the end one character */
  4561.     if (lt(VIsual, curwin->w_cursor))
  4562. pp = &curwin->w_cursor;
  4563.     else
  4564. pp = &VIsual;
  4565.     if (*ml_get_pos(pp) != NUL)
  4566. ++pp->col;
  4567.     else if (pp->lnum < curbuf->b_ml.ml_line_count)
  4568.     {
  4569. ++pp->lnum;
  4570. pp->col = 0;
  4571.     }
  4572.     curwin->w_set_curswant = TRUE;
  4573.     update_curbuf(NOT_VALID);
  4574. }
  4575.     }
  4576. }
  4577. /*
  4578.  * ESC in Normal mode: beep, but don't flush buffers.
  4579.  * Don't even beep if we are canceling a command.
  4580.  */
  4581.     static void
  4582. nv_esc(cap, opnum)
  4583.     CMDARG *cap;
  4584.     linenr_t opnum;
  4585. {
  4586.     if (VIsual_active)
  4587.     {
  4588. end_visual_mode(); /* stop Visual */
  4589. /* leave cursor on first line/col */
  4590. if (lt(VIsual, curwin->w_cursor))
  4591.     curwin->w_cursor = VIsual;
  4592. curwin->w_set_curswant = TRUE;
  4593. update_curbuf(NOT_VALID);
  4594.     }
  4595.     else if (cap->oap->op_type == OP_NOP && opnum == 0 &&
  4596.   cap->count0 == 0 && cap->oap->regname == 0 && !p_im)
  4597. vim_beep();
  4598.     clearop(cap->oap);
  4599.     if (p_im && !restart_edit)
  4600. restart_edit = 'a';
  4601. }
  4602. /*
  4603.  * Handle "A" and "a" command.
  4604.  * Returns command_busy flag.
  4605.  */
  4606.     static int
  4607. nv_append(cap)
  4608.     CMDARG *cap;
  4609. {
  4610.     if (cap->cmdchar == 'a' && (cap->oap->op_type != OP_NOP || VIsual_active))
  4611. #ifdef TEXT_OBJECTS
  4612. nv_object(cap); /* 'a' text object */
  4613. #else
  4614. clearopbeep(cap->oap);
  4615. #endif
  4616.     else
  4617.     {
  4618. if (cap->cmdchar == 'A')
  4619. {
  4620.     curwin->w_set_curswant = TRUE;
  4621.     while (oneright() == OK)
  4622. ;
  4623. }
  4624. if (u_save_cursor() == OK)
  4625. {
  4626.     /* Works just like an 'i'nsert on the next character. */
  4627.     if (!lineempty(curwin->w_cursor.lnum))
  4628. inc_cursor();
  4629.     return edit(cap->cmdchar, FALSE, cap->count1);
  4630. }
  4631.     }
  4632.     return FALSE;
  4633. }
  4634. #ifdef TEXT_OBJECTS
  4635. /*
  4636.  * "a" or "i" while an operator is pending or in Visual mode: object motion.
  4637.  */
  4638.     static void
  4639. nv_object(cap)
  4640.     CMDARG *cap;
  4641. {
  4642.     int flag;
  4643.     int include;
  4644.     char_u *mps_save;
  4645.     if (cap->cmdchar == 'i')
  4646. include = FALSE;    /* "ix" = inner object: exclude white space */
  4647.     else
  4648. include = TRUE;     /* "ax" = an object: include white space */
  4649.     /* Make sure (), [], {} and <> are in 'matchpairs' */
  4650.     mps_save = curbuf->b_p_mps;
  4651.     curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>";
  4652.     switch (cap->nchar)
  4653.     {
  4654. case 'w': /* "aw" = a word */
  4655. flag = current_word(cap->oap, cap->count1, include, FALSE);
  4656. break;
  4657. case 'W': /* "aW" = a WORD */
  4658. flag = current_word(cap->oap, cap->count1, include, TRUE);
  4659. break;
  4660. case 'b': /* "ab" = a braces block */
  4661. case '(':
  4662. case ')':
  4663. flag = current_block(cap->oap, cap->count1, include, '(', ')');
  4664. break;
  4665. case 'B': /* "aB" = a Brackets block */
  4666. case '{':
  4667. case '}':
  4668. flag = current_block(cap->oap, cap->count1, include, '{', '}');
  4669. break;
  4670. case '[': /* "a[" = a [] block */
  4671. case ']':
  4672. flag = current_block(cap->oap, cap->count1, include, '[', ']');
  4673. break;
  4674. case '<': /* "a<" = a <> block */
  4675. case '>':
  4676. flag = current_block(cap->oap, cap->count1, include, '<', '>');
  4677. break;
  4678. case 'p': /* "ap" = a paragraph */
  4679. flag = current_par(cap->oap, cap->count1, include, 'p');
  4680. break;
  4681. case 's': /* "as" = a sentence */
  4682. flag = current_sent(cap->oap, cap->count1, include);
  4683. break;
  4684. #if 0 /* TODO */
  4685. case 'S': /* "aS" = a section */
  4686. case 'f': /* "af" = a filename */
  4687. case 'u': /* "au" = a URL */
  4688. #endif
  4689. default:
  4690. flag = FAIL;
  4691. break;
  4692.     }
  4693.     curbuf->b_p_mps = mps_save;
  4694.     if (flag == FAIL)
  4695. clearopbeep(cap->oap);
  4696.     adjust_cursor_col();
  4697.     curwin->w_set_curswant = TRUE;
  4698. }
  4699. #endif
  4700. /*
  4701.  * Handle the "@r" command.
  4702.  */
  4703.     static void
  4704. nv_at(cap)
  4705.     CMDARG *cap;
  4706. {
  4707.     if (checkclearop(cap->oap))
  4708. return;
  4709. #ifdef WANT_EVAL
  4710.     if (cap->nchar == '=')
  4711.     {
  4712. if (get_expr_register() == NUL)
  4713.     return;
  4714.     }
  4715. #endif
  4716.     while (cap->count1--)
  4717.     {
  4718. if (do_execreg(cap->nchar, FALSE, FALSE) == FAIL)
  4719. {
  4720.     clearopbeep(cap->oap);
  4721.     break;
  4722. }
  4723.     }
  4724. }
  4725. /*
  4726.  * Handle the CTRL-U and CTRL-D commands.
  4727.  */
  4728.     static void
  4729. nv_halfpage(cap)
  4730.     CMDARG *cap;
  4731. {
  4732.     if ((cap->cmdchar == Ctrl('U') && curwin->w_cursor.lnum == 1)
  4733.     || (cap->cmdchar == Ctrl('D')
  4734. && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count))
  4735. clearopbeep(cap->oap);
  4736.     else if (!checkclearop(cap->oap))
  4737. halfpage(cap->cmdchar == Ctrl('D'), cap->count0);
  4738. }
  4739. /*
  4740.  * Handle "J" or "gJ" command.
  4741.  */
  4742.     static void
  4743. nv_join(cap)
  4744.     CMDARG *cap;
  4745. {
  4746.     if (VIsual_active) /* join the visual lines */
  4747. nv_operator(cap);
  4748.     else if (!checkclearop(cap->oap))
  4749.     {
  4750. if (cap->count0 <= 1)
  4751.     cap->count0 = 2;     /* default for join is two lines! */
  4752. if (curwin->w_cursor.lnum + cap->count0 - 1 >
  4753.    curbuf->b_ml.ml_line_count)
  4754.     clearopbeep(cap->oap);  /* beyond last line */
  4755. else
  4756. {
  4757.     prep_redo(cap->oap->regname, cap->count0,
  4758.  cap->oap->op_prechar, cap->cmdchar, NUL, cap->nchar);
  4759.     do_do_join(cap->count0, !cap->oap->op_prechar, TRUE);
  4760. }
  4761.     }
  4762. }
  4763. /*
  4764.  * "P", "gP", "p" and "gp" commands.
  4765.  */
  4766.     static void
  4767. nv_put(cap)
  4768.     CMDARG  *cap;
  4769. {
  4770.     if (cap->oap->op_type != OP_NOP || VIsual_active)
  4771. clearopbeep(cap->oap);
  4772.     else
  4773.     {
  4774. prep_redo_cmd(cap);
  4775. do_put(cap->oap->regname,
  4776. (cap->cmdchar == 'P'
  4777.  || (cap->cmdchar == 'g' && cap->nchar == 'P'))
  4778.  ? BACKWARD : FORWARD,
  4779. cap->count1, cap->cmdchar == 'g' ? PUT_CURSEND : 0);
  4780.     }
  4781. }