home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / amiga / vim46src.lha / vim-4.6 / src / normal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-03-11  |  80.4 KB  |  3,565 lines

  1. /* vi:set ts=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. /*
  10.  * Contains the main routine for processing characters in command mode.
  11.  * Communicates closely with the code in ops.c to handle the operators.
  12.  */
  13.  
  14. #include "vim.h"
  15. #include "globals.h"
  16. #include "proto.h"
  17. #include "option.h"
  18.  
  19. #undef EXTERN
  20. #undef INIT
  21. #define EXTERN
  22. #define INIT(x) x
  23. #include "ops.h"
  24.  
  25. /*
  26.  * Generally speaking, every command in normal() should either clear any
  27.  * pending operator (with clearop()), or set the motion type variable.
  28.  */
  29.  
  30. /*
  31.  * If a count is given before the operator, it is saved in opnum.
  32.  */
  33. static linenr_t    opnum = 0;
  34. static linenr_t    Prenum;         /* The (optional) number before a command. */
  35. static int        prechar = NUL;    /* prepended command char */
  36. /*
  37.  * The visual area is remembered for reselection.
  38.  */
  39. static int        resel_VIsual_mode = NUL;    /* 'v', 'V', or Ctrl-V */
  40. static linenr_t    resel_VIsual_line_count;        /* number of lines */
  41. static colnr_t    resel_VIsual_col;            /* number of cols or end column */
  42.  
  43. #ifdef USE_MOUSE
  44. static void        find_start_of_word __ARGS((FPOS *));
  45. static void        find_end_of_word __ARGS((FPOS *));
  46. static int        get_mouse_class __ARGS((int));
  47. #endif
  48. static void        prep_redo __ARGS((long, int, int, int, int));
  49. static int        checkclearop __ARGS((void));
  50. static int        checkclearopq __ARGS((void));
  51. static void        clearop __ARGS((void));
  52. static void        clearopbeep __ARGS((void));
  53. static void        del_from_showcmd __ARGS((int));
  54. static void        do_gd __ARGS((int nchar));
  55.  
  56. /*
  57.  * normal
  58.  *
  59.  * Execute a command in normal mode.
  60.  *
  61.  * This is basically a big switch with the cases arranged in rough categories
  62.  * in the following order:
  63.  *
  64.  *      0. Macros (q, @)
  65.  *      1. Screen positioning commands (^U, ^D, ^F, ^B, ^E, ^Y, z)
  66.  *      2. Control commands (:, <help>, ^L, ^G, ^^, ZZ, *, ^], ^T)
  67.  *      3. Cursor motions (G, H, M, L, l, K_RIGHT,  , h, K_LEFT, ^H, k, K_UP,
  68.  *         ^P, +, CR, LF, j, K_DOWN, ^N, _, |, B, b, W, w, E, e, $, ^, 0)
  69.  *      4. Searches (?, /, n, N, T, t, F, f, ,, ;, ], [, %, (, ), {, })
  70.  *      5. Edits (., u, K_UNDO, ^R, U, r, J, p, P, ^A, ^S)
  71.  *      6. Inserts (A, a, I, i, o, O, R)
  72.  *      7. Operators (~, d, c, y, >, <, !, =, Q)
  73.  *      8. Abbreviations (x, X, D, C, s, S, Y, &)
  74.  *      9. Marks (m, ', `, ^O, ^I)
  75.  *     10. Buffer setting (")
  76.  *     11. Visual (v, V, ^V)
  77.  *   12. Suspend (^Z)
  78.  *   13. Window commands (^W)
  79.  *   14. extended commands (starting with 'g')
  80.  *   15. mouse click
  81.  *   16. scrollbar movement
  82.  *   17. The end (ESC)
  83.  */
  84.  
  85.     void
  86. normal()
  87. {
  88.     register int    c;
  89.     long             n = 0;                    /* init for GCC */
  90.     int                flag = FALSE;
  91.     int                flag2 = FALSE;
  92.     int             type = 0;                /* type of operation */
  93.     int             dir = FORWARD;            /* search direction */
  94.     int                nchar = NUL;            /* next command char */
  95.     int                finish_op;
  96.     linenr_t        Prenum1;
  97.     char_u            *searchbuff = NULL;        /* buffer for search string */
  98.     FPOS            *pos = NULL;            /* init for gcc */
  99.     char_u            *ptr = NULL;
  100.     int                command_busy = FALSE;
  101.     int                ctrl_w = FALSE;            /* got CTRL-W command */
  102.     int                old_col = 0;
  103.     int                dont_adjust_op_end = FALSE;
  104.     static int        search_dont_set_mark = FALSE;    /* for "*" and "#" */
  105.     FPOS            old_pos;                /* cursor position before command */
  106.  
  107.     Prenum = 0;
  108.     /*
  109.      * If there is an operator pending, then the command we take this time
  110.      * will terminate it. Finish_op tells us to finish the operation before
  111.      * returning this time (unless the operation was cancelled).
  112.      */
  113.     finish_op = (op_type != NOP);
  114.  
  115.     if (!finish_op && !yankbuffer)
  116.         opnum = 0;
  117.  
  118.     State = NORMAL_BUSY;
  119.     c = vgetc();
  120. #ifdef HAVE_LANGMAP
  121.     LANGMAP_ADJUST(c, TRUE);
  122. #endif
  123.     if (c == NUL)
  124.         c = K_ZERO;
  125.     (void)add_to_showcmd(c, FALSE);
  126.  
  127. getcount:
  128.     /* Pick up any leading digits and compute 'Prenum' */
  129.     while ((c >= '1' && c <= '9') || (Prenum != 0 && (c == K_DEL || c == '0')))
  130.     {
  131.         if (c == K_DEL)
  132.         {
  133.             Prenum /= 10;
  134.             del_from_showcmd(4);        /* delete the digit and ~@% */
  135.         }
  136.         else
  137.             Prenum = Prenum * 10 + (c - '0');
  138.         if (Prenum < 0)            /* got too large! */
  139.             Prenum = 999999999;
  140.         if (ctrl_w)
  141.         {
  142.             ++no_mapping;
  143.             ++allow_keys;                /* no mapping for nchar, but keys */
  144.         }
  145.         c = vgetc();
  146. #ifdef HAVE_LANGMAP
  147.         LANGMAP_ADJUST(c, TRUE);
  148. #endif
  149.         if (ctrl_w)
  150.         {
  151.             --no_mapping;
  152.             --allow_keys;
  153.         }
  154.         (void)add_to_showcmd(c, FALSE);
  155.     }
  156.  
  157. /*
  158.  * If we got CTRL-W there may be a/another count
  159.  */
  160.     if (c == Ctrl('W') && !ctrl_w && op_type == NOP)
  161.     {
  162.         ctrl_w = TRUE;
  163.         opnum = Prenum;                        /* remember first count */
  164.         Prenum = 0;
  165.         ++no_mapping;
  166.         ++allow_keys;                        /* no mapping for nchar, but keys */
  167.         c = vgetc();                        /* get next character */
  168. #ifdef HAVE_LANGMAP
  169.         LANGMAP_ADJUST(c, TRUE);
  170. #endif
  171.         --no_mapping;
  172.         --allow_keys;
  173.         (void)add_to_showcmd(c, FALSE);
  174.         goto getcount;                        /* jump back */
  175.     }
  176.  
  177.     /*
  178.      * If we're in the middle of an operator (including after entering a yank
  179.      * buffer with ") AND we had a count before the
  180.      * operator, then that count overrides the current value of Prenum. What
  181.      * this means effectively, is that commands like "3dw" get turned into
  182.      * "d3w" which makes things fall into place pretty neatly.
  183.      * If you give a count before AND after the operator, they are multiplied.
  184.      */
  185.     if (opnum != 0)
  186.     {
  187.             if (Prenum)
  188.                 Prenum *= opnum;
  189.             else
  190.                 Prenum = opnum;
  191.             opnum = 0;
  192.     }
  193.  
  194.     Prenum1 = (Prenum == 0 ? 1 : Prenum);        /* Prenum often defaults to 1 */
  195.  
  196.     /*
  197.      * Get an additional character if we need one.
  198.      * For CTRL-W we already got it when looking for a count.
  199.      */
  200.     if (ctrl_w)
  201.     {
  202.         nchar = c;
  203.         c = Ctrl('W');
  204.     }
  205.     else if ((op_type == NOP && vim_strchr((char_u *)"@zm\"", c) != NULL) ||
  206.             (op_type == NOP && !VIsual_active &&
  207.                  vim_strchr((char_u *)"rZ", c) != NULL) ||
  208.             vim_strchr((char_u *)"tTfF[]g'`", c) != NULL ||
  209.             (c == 'q' && !Recording && !Exec_reg))
  210.     {
  211.         ++no_mapping;
  212.         ++allow_keys;            /* no mapping for nchar, but allow key codes */
  213.         nchar = vgetc();
  214. #ifdef HAVE_LANGMAP
  215.         /* adjust chars > 127: tTfFr should leave lang of nchar unchanged! */
  216.         LANGMAP_ADJUST(nchar, vim_strchr((char_u *)"tTfFr", c) == NULL);
  217. #endif
  218. #ifdef RIGHTLEFT
  219.         if (p_hkmap && strchr("tTfFr", c) && KeyTyped)     /* Hebrew mapped char */
  220.             nchar = hkmap(nchar);
  221. #endif
  222.         --no_mapping;
  223.         --allow_keys;
  224.         (void)add_to_showcmd(nchar, FALSE);
  225.     }
  226.     if (p_sc)
  227.         flushbuf();                /* flush the showcmd characters onto the
  228.                                  * screen so we can see them while the command
  229.                                  * is being executed
  230.                                  */
  231.  
  232.     State = NORMAL;
  233.     if (nchar == ESC)
  234.     {
  235.         clearop();
  236.         goto normal_end;
  237.     }
  238.     msg_didout = FALSE;        /* don't scroll screen up for normal command */
  239.     msg_col = 0;
  240.     old_pos = curwin->w_cursor;            /* remember where cursor was */
  241.  
  242. #ifdef RIGHTLEFT
  243.     if (curwin->w_p_rl && KeyTyped)        /* invert horizontal operations */
  244.         switch (c)
  245.         {
  246.             case 'l':       c = 'h'; break;
  247.             case K_RIGHT:    c = K_LEFT; break;
  248.             case 'h':        c = 'l'; break;
  249.             case K_LEFT:    c = K_RIGHT; break;
  250.             case '>':        c = '<'; break;
  251.             case '<':        c = '>'; break;
  252.         }
  253. #endif
  254.     switch (c)
  255.     {
  256.  
  257. /*
  258.  * 0: Macros
  259.  */
  260.       case 'q':         /* (stop) recording into a named register */
  261.         if (checkclearop())
  262.             break;
  263.                         /* command is ignored while executing a register */
  264.         if (!Exec_reg && do_record(nchar) == FAIL)
  265.             clearopbeep();
  266.         break;
  267.  
  268.      case '@':            /* execute a named buffer */
  269.         if (checkclearop())
  270.             break;
  271.         while (Prenum1--)
  272.         {
  273.             if (do_execbuf(nchar, FALSE, FALSE) == FAIL)
  274.             {
  275.                 clearopbeep();
  276.                 break;
  277.             }
  278.         }
  279.         break;
  280.  
  281. /*
  282.  * 1: Screen positioning commands
  283.  */
  284.       case Ctrl('D'):
  285.         flag = TRUE;
  286.  
  287.       case Ctrl('U'):
  288.         if ((c == Ctrl('U') && curwin->w_cursor.lnum == 1) ||
  289.             (c == Ctrl('D') && curwin->w_cursor.lnum ==
  290.                                                   curbuf->b_ml.ml_line_count))
  291.                 clearopbeep();
  292.         else
  293.         {
  294.             if (checkclearop())
  295.                 break;
  296.             halfpage(flag, Prenum);
  297.         }
  298.         break;
  299.  
  300.       case Ctrl('B'):
  301.       case K_S_UP:
  302.       case K_PAGEUP:
  303.       case K_KPAGEUP:
  304.         dir = BACKWARD;
  305.  
  306.       case Ctrl('F'):
  307.       case K_S_DOWN:
  308.       case K_PAGEDOWN:
  309.       case K_KPAGEDOWN:
  310.         if (checkclearop())
  311.             break;
  312.         (void)onepage(dir, Prenum1);
  313.         break;
  314.  
  315.       case Ctrl('E'):
  316.         if (checkclearop())
  317.             break;
  318.         scrollup(Prenum1);
  319.         if (p_so)
  320.             cursor_correct();
  321.         /* We may have moved to another line -- webb */
  322.         coladvance(curwin->w_curswant);
  323.         cursupdate();
  324.         updateScreen(VALID);
  325.         break;
  326.  
  327.       case Ctrl('Y'):
  328.         if (checkclearop())
  329.             break;
  330.         scrolldown(Prenum1);
  331.         if (p_so)
  332.             cursor_correct();
  333.         /* We may have moved to another line -- webb */
  334.         coladvance(curwin->w_curswant);
  335.         updateScreen(VALID);
  336.         break;
  337.  
  338.       case 'z':
  339.         if (checkclearop())
  340.             break;
  341.         if (nchar < 0x100 && isdigit(nchar))
  342.         {
  343.             Prenum = nchar - '0';
  344.             for (;;)
  345.             {
  346.                 ++no_mapping;
  347.                 ++allow_keys;    /* no mapping for nchar, but allow key codes */
  348.                 nchar = vgetc();
  349. #ifdef HAVE_LANGMAP
  350.                 LANGMAP_ADJUST(c, TRUE);
  351. #endif
  352.                 --no_mapping;
  353.                 --allow_keys;
  354.                 (void)add_to_showcmd(nchar, FALSE);
  355.                 if (c == K_DEL)
  356.                     Prenum /= 10;
  357.                 else if (nchar < 0x100 && isdigit(nchar))
  358.                     Prenum = Prenum * 10 + (nchar - '0');
  359.                 else if (nchar == CR)
  360.                 {
  361.                     win_setheight((int)Prenum);
  362.                     break;
  363.                 }
  364.                 else if (nchar == 'l' || nchar == 'h' ||
  365.                                           nchar == K_LEFT || nchar == K_RIGHT)
  366.                 {
  367.                     Prenum1 = Prenum ? Prenum : 1;
  368.                     goto dozet;
  369.                 }
  370.                 else
  371.                 {
  372.                     clearopbeep();
  373.                     break;
  374.                 }
  375.             }
  376.             op_type = NOP;
  377.             break;
  378.         }
  379. dozet:
  380.         /*
  381.          * If line number given, set cursor, except for "zh", "zl", "ze" and
  382.          * "zs"
  383.          */
  384.         if (vim_strchr((char_u *)"hles", nchar) == NULL &&
  385.                                         nchar != K_LEFT && nchar != K_RIGHT &&
  386.                                     Prenum && Prenum != curwin->w_cursor.lnum)
  387.         {
  388.             setpcmark();
  389.             if (Prenum > curbuf->b_ml.ml_line_count)
  390.                 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  391.             else
  392.                 curwin->w_cursor.lnum = Prenum;
  393.         }
  394.         switch (nchar)
  395.         {
  396.           case NL:                /* put curwin->w_cursor at top of screen */
  397.           case CR:
  398.             beginline(TRUE);
  399.             /* FALLTHROUGH */
  400.           case 't':
  401.             scroll_cursor_top(0, TRUE);
  402.             break;
  403.  
  404.           case '.':             /* put curwin->w_cursor in middle of screen */
  405.             beginline(TRUE);
  406.             /* FALLTHROUGH */
  407.           case 'z':
  408.             scroll_cursor_halfway(TRUE);
  409.             break;
  410.  
  411.           case '-':             /* put curwin->w_cursor at bottom of screen */
  412.             beginline(TRUE);
  413.             /* FALLTHROUGH */
  414.           case 'b':
  415.             scroll_cursor_bot(0, TRUE);
  416.             break;
  417.  
  418.             /* "zh" - scroll screen to the right */
  419.           case 'h':
  420.           case K_LEFT:
  421.             if (!curwin->w_p_wrap)
  422.             {
  423.                 colnr_t        s, e;
  424.  
  425.                 if ((colnr_t)Prenum1 > curwin->w_leftcol)
  426.                     curwin->w_leftcol = 0;
  427.                 else
  428.                     curwin->w_leftcol -= (colnr_t)Prenum1;
  429.                 n = curwin->w_leftcol + Columns -
  430.                     (curwin->w_p_nu ? 8 : 0) - 1;
  431.                 if (curwin->w_virtcol > (colnr_t)n)
  432.                     coladvance((colnr_t)n);
  433.  
  434.                 getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
  435.                 if (e > (colnr_t)n)
  436.                     coladvance(s - 1);
  437.                 redraw_later(NOT_VALID);
  438.             }
  439.             break;
  440.  
  441.             /* "zl" - scroll screen to the left */
  442.           case 'l':
  443.           case K_RIGHT:
  444.             if (!curwin->w_p_wrap)
  445.             {
  446.                 colnr_t        s, e;
  447.  
  448.                 /* scroll the window left */
  449.                 curwin->w_leftcol += (colnr_t)Prenum1;
  450.  
  451.                 /* If the cursor has moved off the screen, put it at the
  452.                  * first char on the screen */
  453.                 if (curwin->w_leftcol > curwin->w_virtcol)
  454.                     (void)coladvance(curwin->w_leftcol);
  455.  
  456.                 /* If the start of the character under the cursor is not
  457.                  * on the screen, advance the cursor one more char.  If
  458.                  * this fails (last char of the line) adjust the
  459.                  * scrolling. */
  460.                 getvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
  461.                 if (s < curwin->w_leftcol)
  462.                     if (coladvance(e + 1) == FAIL)
  463.                         curwin->w_leftcol = s;
  464.  
  465.                 redraw_later(NOT_VALID);
  466.             }
  467.             break;
  468.  
  469.             /* "zs" - scroll screen, cursor at the start */
  470.           case 's':
  471.             if (!curwin->w_p_wrap)
  472.             {
  473.                 colnr_t        s;
  474.  
  475.                 getvcol(curwin, &curwin->w_cursor, &s, NULL, NULL);
  476.                 curwin->w_leftcol = s;
  477.                 redraw_later(NOT_VALID);
  478.             }
  479.             break;
  480.  
  481.             /* "ze" - scroll screen, cursor at the end */
  482.           case 'e':
  483.             if (!curwin->w_p_wrap)
  484.             {
  485.                 colnr_t        e;
  486.  
  487.                 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &e);
  488.                 if ((long)e < Columns)
  489.                     curwin->w_leftcol = 0;
  490.                 else
  491.                     curwin->w_leftcol = e - Columns + 1;
  492.                 redraw_later(NOT_VALID);
  493.             }
  494.             break;
  495.  
  496.           case Ctrl('S'):    /* ignore CTRL-S and CTRL-Q to avoid problems */
  497.           case Ctrl('Q'):    /* with terminals that use xon/xoff */
  498.               break;
  499.  
  500.           default:
  501.             clearopbeep();
  502.         }
  503.         updateScreen(VALID);
  504.         break;
  505.  
  506. /*
  507.  *      2: Control commands
  508.  */
  509.       case ':':
  510.         if (VIsual_active)
  511.             goto dooperator;
  512.         if (checkclearop())
  513.             break;
  514.         /*
  515.          * translate "count:" into ":.,.+(count - 1)"
  516.          */
  517.         if (Prenum)
  518.         {
  519.             stuffReadbuff((char_u *)".");
  520.             if (Prenum > 1)
  521.             {
  522.                 stuffReadbuff((char_u *)",.+");
  523.                 stuffnumReadbuff((long)Prenum - 1L);
  524.             }
  525.         }
  526.         do_cmdline(NULL, FALSE, FALSE);
  527.         break;
  528.  
  529.       case K_HELP:
  530.       case K_F1:
  531.         if (checkclearopq())
  532.             break;
  533.         do_help((char_u *)"");
  534.         break;
  535.  
  536.       case Ctrl('L'):
  537.         if (checkclearop())
  538.             break;
  539.         updateScreen(CLEAR);
  540.         break;
  541.  
  542.       case Ctrl('G'):
  543.         if (checkclearop())
  544.             break;
  545.             /* print full name if count given or :cd used */
  546.         fileinfo(did_cd | (int)Prenum, FALSE, FALSE);
  547.         break;
  548.  
  549.       case K_CCIRCM:            /* CTRL-^, short for ":e #" */
  550.         if (checkclearopq())
  551.             break;
  552.         (void)buflist_getfile((int)Prenum, (linenr_t)0,
  553.                                                 GETF_SETMARK|GETF_ALT, FALSE);
  554.         break;
  555.  
  556.         /*
  557.          * "ZZ": write if changed, and exit window
  558.          * "ZQ": quit window (Elvis compatible)
  559.          */
  560.       case 'Z':
  561.         if (checkclearopq())
  562.             break;
  563.         if (nchar == 'Z')
  564.             stuffReadbuff((char_u *)":x\n");
  565.         else if (nchar == 'Q')
  566.             stuffReadbuff((char_u *)":q!\n");
  567.         else
  568.             clearopbeep();
  569.         break;
  570.  
  571.       case Ctrl(']'):            /* :ta to current identifier */
  572.       case 'K':                    /* run program for current identifier */
  573.         if (VIsual_active)        /* :ta to visual highlighted text */
  574.         {
  575.             if (VIsual.lnum != curwin->w_cursor.lnum)
  576.             {
  577.                 clearopbeep();
  578.                 break;
  579.             }
  580.             if (lt(curwin->w_cursor, VIsual))
  581.             {
  582.                 ptr = ml_get_pos(&curwin->w_cursor);
  583.                 n = VIsual.col - curwin->w_cursor.col + 1;
  584.             }
  585.             else
  586.             {
  587.                 ptr = ml_get_pos(&VIsual);
  588.                 n = curwin->w_cursor.col - VIsual.col + 1;
  589.             }
  590.             end_visual_mode();
  591.             ++RedrawingDisabled;
  592.             update_curbuf(NOT_VALID);        /* update the inversion later */
  593.             --RedrawingDisabled;
  594.         }
  595.         if (checkclearopq())
  596.             break;
  597.         /*FALLTHROUGH*/
  598.  
  599.       case 163:                    /* the pound sign, '#' for English keyboards */
  600.         if (c == 163)
  601.               c = '#';
  602.         /*FALLTHROUGH*/
  603.  
  604.       case '*':                 /* / to current identifier or string */
  605.       case '#':                 /* ? to current identifier or string */
  606. search_word:
  607.         if (c == 'g')
  608.             type = nchar;        /* "g*" or "g#" */
  609.         else
  610.             type = c;
  611.         if (ptr == NULL && (n = find_ident_under_cursor(&ptr, (type == '*' ||
  612.                     type == '#') ? FIND_IDENT|FIND_STRING : FIND_IDENT)) == 0)
  613.         {
  614.             clearop();
  615.             break;
  616.         }
  617.  
  618.         if (Prenum)
  619.             stuffnumReadbuff(Prenum);
  620.         switch (type)
  621.         {
  622.             case '*':
  623.                 stuffReadbuff((char_u *)"/");
  624.                 /* FALLTHROUGH */
  625.  
  626.             case '#':
  627.                 if (type == '#')
  628.                     stuffReadbuff((char_u *)"?");
  629.  
  630.                 /*
  631.                  * Put cursor at start of word, makes search skip the word
  632.                  * under the cursor.
  633.                  * Call setpcmark() first, so "*``" puts the cursor back where
  634.                  * it was, and set search_dont_set_mark to avoid doing it
  635.                  * again when searching.
  636.                  */
  637.                 setpcmark();
  638.                 search_dont_set_mark = TRUE;
  639.                 curwin->w_cursor.col = ptr - ml_get_curline();
  640.  
  641.                 if (c != 'g' && iswordchar(*ptr))
  642.                     stuffReadbuff((char_u *)"\\<");
  643.                 no_smartcase = TRUE;        /* don't use 'smartcase' now */
  644.                 break;
  645.  
  646.             case 'K':
  647.                 if (*p_kp == NUL)
  648.                     stuffReadbuff((char_u *)":he ");
  649.                 else
  650.                 {
  651.                     stuffReadbuff((char_u *)":! ");
  652.                     stuffReadbuff(p_kp);
  653.                     stuffReadbuff((char_u *)" ");
  654.                 }
  655.                 break;
  656.             default:
  657.                 if (curbuf->b_help)
  658.                     stuffReadbuff((char_u *)":he ");
  659.                 else
  660.                     stuffReadbuff((char_u *)":ta ");
  661.         }
  662.  
  663.         /*
  664.          * Now grab the chars in the identifier
  665.          */
  666.         while (n--)
  667.         {
  668.                 /* put a backslash before \ and some others */
  669.             if (*ptr == '\\' || (!(type == '*' || type == '#') &&
  670.                                       vim_strchr(escape_chars, *ptr) != NULL))
  671.                 stuffcharReadbuff('\\');
  672.                 /* don't interpret the characters as edit commands */
  673.             if (*ptr < ' ' || *ptr > '~')
  674.                 stuffcharReadbuff(Ctrl('V'));
  675.             stuffcharReadbuff(*ptr++);
  676.         }
  677.  
  678.         if (c != 'g' && (type == '*' || type == '#') && iswordchar(ptr[-1]))
  679.             stuffReadbuff((char_u *)"\\>");
  680.         stuffReadbuff((char_u *)"\n");
  681.         break;
  682.  
  683.       case Ctrl('T'):        /* backwards in tag stack */
  684.         if (checkclearopq())
  685.             break;
  686.         do_tag((char_u *)"", 2, (int)Prenum1, FALSE);
  687.         break;
  688.  
  689. /*
  690.  * Cursor motions
  691.  */
  692.       case 'G':
  693. goto_line:
  694.         op_motion_type = MLINE;
  695.         setpcmark();
  696.         if (Prenum == 0 || Prenum > curbuf->b_ml.ml_line_count)
  697.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  698.         else
  699.             curwin->w_cursor.lnum = Prenum;
  700.         beginline(MAYBE);
  701.         break;
  702.  
  703.       case 'H':
  704.       case 'M':
  705.         if (c == 'M')
  706.         {
  707.             int        used = 0;
  708.  
  709.             for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; ++n)
  710.                 if ((used += plines(curwin->w_topline + n)) >=
  711.                             (curwin->w_height - curwin->w_empty_rows + 1) / 2)
  712.                     break;
  713.             if (n && used > curwin->w_height)
  714.                 --n;
  715.         }
  716.         else
  717.             n = Prenum1 - 1;
  718.         op_motion_type = MLINE;
  719.         setpcmark();
  720.         curwin->w_cursor.lnum = curwin->w_topline + n;
  721.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  722.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  723.         cursor_correct();        /* correct for 'so' */
  724.         beginline(MAYBE);
  725.         break;
  726.  
  727.       case 'L':
  728.         op_motion_type = MLINE;
  729.         setpcmark();
  730.         curwin->w_cursor.lnum = curwin->w_botline - 1;
  731.         if (Prenum1 - 1 >= curwin->w_cursor.lnum)
  732.             curwin->w_cursor.lnum = 1;
  733.         else
  734.             curwin->w_cursor.lnum -= Prenum1 - 1;
  735.         cursor_correct();        /* correct for 'so' */
  736.         beginline(MAYBE);
  737.         break;
  738.  
  739.       case 'l':
  740.       case K_RIGHT:
  741.       case ' ':
  742.         op_motion_type = MCHAR;
  743.         op_inclusive = FALSE;
  744.         n = Prenum1;
  745.         while (n--)
  746.         {
  747.             if (oneright() == FAIL)
  748.             {
  749.                     /* space wraps to next line if 'whichwrap' bit 1 set */
  750.                     /* 'l' wraps to next line if 'whichwrap' bit 2 set */
  751.                     /* CURS_RIGHT wraps to next line if 'whichwrap' bit 3 set */
  752.                 if (((c == ' '     && vim_strchr(p_ww, 's') != NULL) ||
  753.                      (c == 'l'     && vim_strchr(p_ww, 'l') != NULL) ||
  754.                      (c == K_RIGHT && vim_strchr(p_ww, '>') != NULL)) &&
  755.                          curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  756.                 {
  757.                     /* When deleting we also count the NL as a character.
  758.                      * Set op_inclusive when last char in the line is
  759.                      * included, move to next line after that */
  760.                     if ((op_type == DELETE || op_type == CHANGE) &&
  761.                            !op_inclusive && !lineempty(curwin->w_cursor.lnum))
  762.                         op_inclusive = TRUE;
  763.                     else
  764.                     {
  765.                         ++curwin->w_cursor.lnum;
  766.                         curwin->w_cursor.col = 0;
  767.                         curwin->w_set_curswant = TRUE;
  768.                         op_inclusive = FALSE;
  769.                     }
  770.                     continue;
  771.                 }
  772.                 if (op_type == NOP)
  773.                     beep_flush();
  774.                 else
  775.                 {
  776.                     if (lineempty(curwin->w_cursor.lnum))
  777.                         clearopbeep();
  778.                     else
  779.                     {
  780.                         op_inclusive = TRUE;
  781.                         if (n)
  782.                             beep_flush();
  783.                     }
  784.                 }
  785.                 break;
  786.             }
  787.         }
  788.         break;
  789.  
  790.       case 'h':
  791.       case K_LEFT:
  792.       case K_BS:
  793.       case Ctrl('H'):
  794.         op_motion_type = MCHAR;
  795.         op_inclusive = FALSE;
  796.         n = Prenum1;
  797.         while (n--)
  798.         {
  799.             if (oneleft() == FAIL)
  800.             {
  801.                     /* backspace and del wrap to previous line if 'whichwrap'
  802.                      *       bit 0 set.
  803.                      * 'h' wraps to previous line if 'whichwrap' bit 2 set.
  804.                      * CURS_LEFT wraps to previous line if 'whichwrap' bit 3
  805.                      * set. */
  806.                 if (   (((c == K_BS || c == Ctrl('H'))
  807.                                      && vim_strchr(p_ww, 'b') != NULL) ||
  808.                         (c == 'h'    && vim_strchr(p_ww, 'h') != NULL) ||
  809.                         (c == K_LEFT && vim_strchr(p_ww, '<') != NULL)) &&
  810.                             curwin->w_cursor.lnum > 1)
  811.                 {
  812.                     --(curwin->w_cursor.lnum);
  813.                     coladvance(MAXCOL);
  814.                     curwin->w_set_curswant = TRUE;
  815.  
  816.                     /* When the NL before the first char has to be deleted we
  817.                      * put the cursor on the NUL after the previous line.
  818.                      * This is a very special case, be careful!
  819.                      * don't adjust op_end now, otherwise it won't work */
  820.                     if ((op_type == DELETE || op_type == CHANGE) &&
  821.                                             !lineempty(curwin->w_cursor.lnum))
  822.                     {
  823.                         ++curwin->w_cursor.col;
  824.                         dont_adjust_op_end = TRUE;
  825.                     }
  826.                     continue;
  827.                 }
  828.                 else if (op_type != DELETE && op_type != CHANGE)
  829.                     beep_flush();
  830.                 else if (Prenum1 == 1)
  831.                     clearopbeep();
  832.                 break;
  833.             }
  834.         }
  835.         break;
  836.  
  837.       case '-':
  838.         flag = TRUE;
  839.         /* FALLTHROUGH */
  840.  
  841.       case 'k':
  842.       case K_UP:
  843.       case Ctrl('P'):
  844. normal_k:
  845.         op_motion_type = MLINE;
  846.         if (cursor_up(Prenum1) == FAIL)
  847.             clearopbeep();
  848.         else if (flag)
  849.             beginline(TRUE);
  850.         break;
  851.  
  852.       case '+':
  853.       case CR:
  854.         flag = TRUE;
  855.         /* FALLTHROUGH */
  856.  
  857.       case 'j':
  858.       case K_DOWN:
  859.       case Ctrl('N'):
  860.       case NL:
  861. normal_j:
  862.         op_motion_type = MLINE;
  863.         if (cursor_down(Prenum1) == FAIL)
  864.             clearopbeep();
  865.         else if (flag)
  866.             beginline(TRUE);
  867.         break;
  868.  
  869.         /*
  870.          * This is a strange motion command that helps make operators more
  871.          * logical. It is actually implemented, but not documented in the
  872.          * real 'vi'. This motion command actually refers to "the current
  873.          * line". Commands like "dd" and "yy" are really an alternate form of
  874.          * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
  875.          * lines.
  876.          */
  877.       case '_':
  878. lineop:
  879.         old_col = curwin->w_curswant;
  880.         op_motion_type = MLINE;
  881.         if (cursor_down((long)(Prenum1 - 1)) == FAIL)
  882.             clearopbeep();
  883.         if (op_type == DELETE || op_type == LSHIFT || op_type == RSHIFT)
  884.             beginline(MAYBE);
  885.         else if (op_type != YANK)            /* 'Y' does not move cursor */
  886.             beginline(TRUE);
  887.         break;
  888.  
  889.       case K_HOME:
  890.       case K_KHOME:
  891.         if ((mod_mask & MOD_MASK_CTRL))
  892.             goto goto_line_one;
  893.         Prenum = 1;
  894.         /* FALLTHROUGH */
  895.  
  896.       case '|':
  897.         op_motion_type = MCHAR;
  898.         op_inclusive = FALSE;
  899.         beginline(FALSE);
  900.         if (Prenum > 0)
  901.         {
  902.             coladvance((colnr_t)(Prenum - 1));
  903.             curwin->w_curswant = (colnr_t)(Prenum - 1);
  904.         }
  905.         else
  906.             curwin->w_curswant = 0;
  907.         /* keep curswant at the column where we wanted to go, not where
  908.                 we ended; differs is line is too short */
  909.         curwin->w_set_curswant = FALSE;
  910.         break;
  911.  
  912.         /*
  913.          * Word Motions
  914.          */
  915.  
  916.       case 'B':
  917.         type = 1;
  918.         /* FALLTHROUGH */
  919.  
  920.       case 'b':
  921.       case K_S_LEFT:
  922.         op_motion_type = MCHAR;
  923.         op_inclusive = FALSE;
  924.         curwin->w_set_curswant = TRUE;
  925.         if (bck_word(Prenum1, type, FALSE) == FAIL)
  926.             clearopbeep();
  927.         break;
  928.  
  929.       case 'E':
  930.         type = 1;
  931.         /* FALLTHROUGH */
  932.  
  933.       case 'e':
  934.         op_inclusive = TRUE;
  935.         goto dowrdcmd;
  936.  
  937.       case 'W':
  938.         type = 1;
  939.         /* FALLTHROUGH */
  940.  
  941.       case 'w':
  942.       case K_S_RIGHT:
  943.         op_inclusive = FALSE;
  944.         flag = TRUE;
  945.  
  946.         /*
  947.          * "cw" and "cW" are a special case.
  948.          */
  949.         if (op_type == CHANGE)
  950.         {
  951.             n = gchar_cursor();
  952.             if (n != NUL)                    /* not an empty line */
  953.             {
  954.                 if (vim_iswhite(n))
  955.                 {
  956.                     /*
  957.                      * Reproduce a funny Vi behaviour: "cw" on a blank only
  958.                      * changes one character, not all blanks until the start
  959.                      * of the next word.  Only do this when the 'w' flag is
  960.                      * included in 'cpoptions'.
  961.                      */
  962.                     if (Prenum1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
  963.                     {
  964.                         op_inclusive = TRUE;
  965.                         op_motion_type = MCHAR;
  966.                         break;
  967.                     }
  968.                 }
  969.                 else
  970.                 {
  971.                     /*
  972.                      * This is a little strange. To match what the real vi
  973.                      * does, we effectively map 'cw' to 'ce', and 'cW' to
  974.                      * 'cE', provided that we are not on a space or a TAB.
  975.                      * This seems impolite at first, but it's really more what
  976.                      * we mean when we say 'cw'.
  977.                      * Another strangeness: When standing on the end of a word
  978.                      * "ce" will change until the end of the next wordt, but
  979.                      * "cw" will change only one character! This is done by
  980.                      * setting flag2.
  981.                      */
  982.                     op_inclusive = TRUE;
  983.                     flag = FALSE;
  984.                     flag2 = TRUE;
  985.                 }
  986.             }
  987.         }
  988.  
  989. dowrdcmd:
  990.         op_motion_type = MCHAR;
  991.         curwin->w_set_curswant = TRUE;
  992.         if (flag)
  993.             n = fwd_word(Prenum1, type, op_type != NOP);
  994.         else
  995.             n = end_word(Prenum1, type, flag2, FALSE);
  996.         if (n == FAIL)
  997.             clearopbeep();
  998.         break;
  999.  
  1000.       case K_END:
  1001.       case K_KEND:
  1002.         if ((mod_mask & MOD_MASK_CTRL))
  1003.             goto goto_line;
  1004.         /* FALLTHROUGH */
  1005.  
  1006.       case '$':
  1007.         op_motion_type = MCHAR;
  1008.         op_inclusive = TRUE;
  1009.         curwin->w_curswant = MAXCOL;                /* so we stay at the end */
  1010.         if (cursor_down((long)(Prenum1 - 1)) == FAIL)
  1011.         {
  1012.             clearopbeep();
  1013.             break;
  1014.         }
  1015.         break;
  1016.  
  1017.       case '^':
  1018.         flag = TRUE;
  1019.         /* FALLTHROUGH */
  1020.  
  1021.       case '0':
  1022.         op_motion_type = MCHAR;
  1023.         op_inclusive = FALSE;
  1024.         beginline(flag);
  1025.         break;
  1026.  
  1027. /*
  1028.  * 4: Searches
  1029.  */
  1030.       case '?':
  1031.       case '/':
  1032.         if ((searchbuff = getcmdline(c, Prenum1)) == NULL)
  1033.         {
  1034.             clearop();
  1035.             break;
  1036.         }
  1037.         op_motion_type = MCHAR;
  1038.         op_inclusive = FALSE;
  1039.         curwin->w_set_curswant = TRUE;
  1040.  
  1041.         n = do_search(c, searchbuff, Prenum1,
  1042.                 (search_dont_set_mark ? 0 : SEARCH_MARK) |
  1043.                 SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG);
  1044.         if (n == 0)
  1045.             clearop();
  1046.         else if (n == 2)
  1047.             op_motion_type = MLINE;
  1048.         search_dont_set_mark = FALSE;
  1049.         break;
  1050.  
  1051.       case 'N':
  1052.         flag = SEARCH_REV;
  1053.  
  1054.       case 'n':
  1055.         op_motion_type = MCHAR;
  1056.         op_inclusive = FALSE;
  1057.         curwin->w_set_curswant = TRUE;
  1058.         if (!do_search(0, NULL, Prenum1,
  1059.                   SEARCH_MARK | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG | flag))
  1060.             clearop();
  1061.         break;
  1062.  
  1063.         /*
  1064.          * Character searches
  1065.          */
  1066.       case 'T':
  1067.         dir = BACKWARD;
  1068.         /* FALLTHROUGH */
  1069.  
  1070.       case 't':
  1071.         type = 1;
  1072.         goto docsearch;
  1073.  
  1074.       case 'F':
  1075.         dir = BACKWARD;
  1076.         /* FALLTHROUGH */
  1077.  
  1078.       case 'f':
  1079. docsearch:
  1080.         op_motion_type = MCHAR;
  1081.         if (dir == BACKWARD)
  1082.             op_inclusive = FALSE;
  1083.         else
  1084.             op_inclusive = TRUE;
  1085.         curwin->w_set_curswant = TRUE;
  1086.         if (nchar >= 0x100 || !searchc(nchar, dir, type, Prenum1))
  1087.             clearopbeep();
  1088.         break;
  1089.  
  1090.       case ',':
  1091.         flag = 1;
  1092.         /* FALLTHROUGH */
  1093.  
  1094.       case ';':
  1095.         dir = flag;
  1096.         goto docsearch;        /* nchar == NUL, thus repeat previous search */
  1097.  
  1098.         /*
  1099.          * section or C function searches
  1100.          */
  1101.       case '[':
  1102.         dir = BACKWARD;
  1103.         /* FALLTHROUGH */
  1104.  
  1105.       case ']':
  1106.         op_motion_type = MCHAR;
  1107.         op_inclusive = FALSE;
  1108.  
  1109.         /*
  1110.          * "[f" or "]f" : Edit file under the cursor (same as "gf")
  1111.          */
  1112.         if (nchar == 'f')
  1113.             goto gotofile;
  1114.  
  1115.         /*
  1116.          * Find the occurence(s) of the identifier or define under cursor
  1117.          * in current and included files or jump to the first occurence.
  1118.          *
  1119.          *                     search          list            jump 
  1120.          *                   fwd   bwd    fwd   bwd     fwd    bwd
  1121.          * identifier     "]i"  "[i"   "]I"  "[I"   "]^I"  "[^I"
  1122.          * define          "]d"  "[d"   "]D"  "[D"   "]^D"  "[^D"
  1123.          */
  1124.         if (nchar == 'i' || nchar == 'I' || nchar == Ctrl('I') ||
  1125.             nchar == 'd' || nchar == 'D' || nchar == Ctrl('D'))
  1126.         {
  1127.             int            len;
  1128.  
  1129.             if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
  1130.             {
  1131.                 clearop();
  1132.                 break;
  1133.             }
  1134.             find_pattern_in_path(ptr, len, TRUE,
  1135.                 Prenum == 0 ? !isupper(nchar) : FALSE,
  1136.                 ((nchar & 0xf) == ('d' & 0xf)) ?  FIND_DEFINE : FIND_ANY,
  1137.                 Prenum1,
  1138.                 isupper(nchar) ? ACTION_SHOW_ALL :
  1139.                             islower(nchar) ? ACTION_SHOW : ACTION_GOTO,
  1140.                 c == ']' ? curwin->w_cursor.lnum : (linenr_t)1,
  1141.                 (linenr_t)MAXLNUM);
  1142.             curwin->w_set_curswant = TRUE;
  1143.             break;
  1144.         }
  1145.  
  1146.         /*
  1147.          * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
  1148.          * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
  1149.          * "[/", "[*", "]/", "]*": go to Nth comment start/end.
  1150.          */
  1151.         if ((c == '[' && vim_strchr((char_u *)"{(*/#", nchar) != NULL) ||
  1152.             (c == ']' && vim_strchr((char_u *)"})*/#", nchar) != NULL))
  1153.         {
  1154.             FPOS new_pos;
  1155.  
  1156.             if (nchar == '*')
  1157.                 nchar = '/';
  1158.             new_pos.lnum = 0;
  1159.             while (Prenum1--)
  1160.             {
  1161.                 if ((pos = findmatchlimit(nchar,
  1162.                            (c == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
  1163.                 {
  1164.                     if (new_pos.lnum == 0)    /* nothing found */
  1165.                         clearopbeep();
  1166.                     else
  1167.                         pos = &new_pos;        /* use last one found */
  1168.                     break;
  1169.                 }
  1170.                 curwin->w_cursor = *pos;
  1171.                 new_pos= *pos;
  1172.             }
  1173.             curwin->w_cursor = old_pos;
  1174.             if (pos != NULL)
  1175.             {
  1176.                 setpcmark();
  1177.                 curwin->w_cursor = *pos;
  1178.                 curwin->w_set_curswant = TRUE;
  1179.             }
  1180.             break;
  1181.         }
  1182.  
  1183.         /*
  1184.          * "[[", "[]", "]]" and "][": move to start or end of function
  1185.          */
  1186.         if (nchar == '[' || nchar == ']')
  1187.         {
  1188.             if (nchar == c)                /* "]]" or "[[" */
  1189.                 flag = '{';
  1190.             else
  1191.                 flag = '}';                /* "][" or "[]" */
  1192.  
  1193.             curwin->w_set_curswant = TRUE;
  1194.             /*
  1195.              * Imitate strange vi behaviour: When using "]]" with an operator
  1196.              * we also stop at '}'.
  1197.              */
  1198.             if (!findpar(dir, Prenum1, flag,
  1199.                            (op_type != NOP && dir == FORWARD && flag == '{')))
  1200.                 clearopbeep();
  1201.             else if (op_type == NOP)
  1202.                 beginline(TRUE);
  1203.             break;
  1204.         }
  1205.  
  1206.         /*
  1207.          * "[p", "[P", "]P" and "]p": put with indent adjustment
  1208.          */
  1209.         if (nchar == 'p' || nchar == 'P')
  1210.         {
  1211.             if (checkclearopq())
  1212.                 break;
  1213.             prep_redo(Prenum, NUL, c, nchar, NUL);
  1214.             do_put((c == ']' && nchar == 'p') ? FORWARD : BACKWARD,
  1215.                                                             Prenum1, TRUE);
  1216.             break;
  1217.         }
  1218.  
  1219. #ifdef USE_MOUSE
  1220.         /*
  1221.          * [ or ] followed by a middle mouse click: put selected text with
  1222.          * indent adjustment.  Any other button just does as usual.
  1223.          */
  1224.         if (nchar >= K_LEFTMOUSE && nchar <= K_RIGHTRELEASE)
  1225.         {
  1226.             (void)do_mouse(nchar, (c == ']') ? FORWARD : BACKWARD,
  1227.                                                                Prenum1, TRUE);
  1228.             break;
  1229.         }
  1230. #endif /* USE_MOUSE */
  1231.  
  1232.         /*
  1233.          * end of '[' and ']': not a valid nchar
  1234.          */
  1235.         clearopbeep();
  1236.         break;
  1237.  
  1238.       case '%':
  1239.         op_inclusive = TRUE;
  1240.         if (Prenum)        /* {cnt}% : goto {cnt} percentage in file */
  1241.         {
  1242.             if (Prenum > 100)
  1243.                 clearopbeep();
  1244.             else
  1245.             {
  1246.                 op_motion_type = MLINE;
  1247.                 setpcmark();
  1248.                         /* round up, so CTRL-G will give same value */
  1249.                 curwin->w_cursor.lnum = (curbuf->b_ml.ml_line_count *
  1250.                                                            Prenum + 99) / 100;
  1251.                 beginline(MAYBE);
  1252.             }
  1253.         }
  1254.         else            /* % : go to matching paren */
  1255.         {
  1256.             op_motion_type = MCHAR;
  1257.             if ((pos = findmatch(NUL)) == NULL)
  1258.                 clearopbeep();
  1259.             else
  1260.             {
  1261.                 setpcmark();
  1262.                 curwin->w_cursor = *pos;
  1263.                 curwin->w_set_curswant = TRUE;
  1264.             }
  1265.         }
  1266.         break;
  1267.  
  1268.       case '(':
  1269.         dir = BACKWARD;
  1270.         /* FALLTHROUGH */
  1271.  
  1272.       case ')':
  1273.         op_motion_type = MCHAR;
  1274.         if (c == ')')
  1275.             op_inclusive = FALSE;
  1276.         else
  1277.             op_inclusive = TRUE;
  1278.         curwin->w_set_curswant = TRUE;
  1279.  
  1280.         if (findsent(dir, Prenum1) == FAIL)
  1281.             clearopbeep();
  1282.         break;
  1283.  
  1284.       case '{':
  1285.         dir = BACKWARD;
  1286.         /* FALLTHROUGH */
  1287.  
  1288.       case '}':
  1289.         op_motion_type = MCHAR;
  1290.         op_inclusive = FALSE;
  1291.         curwin->w_set_curswant = TRUE;
  1292.         if (!findpar(dir, Prenum1, NUL, FALSE))
  1293.             clearopbeep();
  1294.         break;
  1295.  
  1296. /*
  1297.  * 5: Edits
  1298.  */
  1299.       case '.':                /* redo command */
  1300.         if (checkclearopq())
  1301.             break;
  1302.         /*
  1303.          * if restart_edit is TRUE, the last but one command is repeated
  1304.          * instead of the last command (inserting text). This is used for
  1305.          * CTRL-O <.> in insert mode
  1306.          */
  1307.         if (start_redo(Prenum, restart_edit && !arrow_used) == FAIL)
  1308.             clearopbeep();
  1309.         break;
  1310.  
  1311.       case 'u':                /* undo */
  1312.         if (VIsual_active || op_type == vim_strchr(opchars, 'u') - opchars + 1)
  1313.             goto dooperator;
  1314.       case K_UNDO:
  1315.         if (checkclearopq())
  1316.             break;
  1317.         u_undo((int)Prenum1);
  1318.         curwin->w_set_curswant = TRUE;
  1319.         break;
  1320.  
  1321.       case Ctrl('R'):        /* undo undo */
  1322.         if (checkclearopq())
  1323.             break;
  1324.           u_redo((int)Prenum1);
  1325.         curwin->w_set_curswant = TRUE;
  1326.         break;
  1327.  
  1328.       case 'U':                /* Undo line */
  1329.         if (VIsual_active || op_type == vim_strchr(opchars, 'U') - opchars + 1)
  1330.             goto dooperator;
  1331.         if (checkclearopq())
  1332.             break;
  1333.         u_undoline();
  1334.         curwin->w_set_curswant = TRUE;
  1335.         break;
  1336.  
  1337.       case 'r':
  1338.         if (VIsual_active)
  1339.         {
  1340.             c = 'c';
  1341.             goto dooperator;
  1342.         }
  1343.         if (checkclearop())
  1344.             break;
  1345.         ptr = ml_get_cursor();
  1346.             /* special key or not enough characters to replace */
  1347.         if (nchar >= 0x100 || STRLEN(ptr) < (unsigned)Prenum1)
  1348.         {
  1349.             clearopbeep();
  1350.             break;
  1351.         }
  1352.         /*
  1353.          * Replacing with a TAB is done by edit(), because it is complicated
  1354.          * when 'expandtab' or 'smarttab' is set.
  1355.          * Other characters are done below to avoid problems with things like
  1356.          * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
  1357.          */
  1358.         if (nchar == '\t' && (curbuf->b_p_et || p_sta))
  1359.         {
  1360.             stuffnumReadbuff(Prenum1);
  1361.             stuffcharReadbuff('R');
  1362.             stuffcharReadbuff('\t');
  1363.             stuffcharReadbuff(ESC);
  1364.             break;
  1365.         }
  1366.  
  1367.         if (nchar == Ctrl('V'))                /* get another character */
  1368.         {
  1369.             c = Ctrl('V');
  1370.             nchar = get_literal();
  1371.         }
  1372.         else
  1373.             c = NUL;
  1374.         if (u_save_cursor() == FAIL)        /* save line for undo */
  1375.             break;
  1376.         /*
  1377.          * Replace character(s) by a single newline.
  1378.          * Strange vi behaviour: Only one newline is inserted.
  1379.          * Delete the characters here.
  1380.          * Insert the newline with an insert command, takes care of
  1381.          * autoindent.
  1382.          */
  1383.         if (c != Ctrl('V') && (nchar == '\r' || nchar == '\n'))
  1384.         {
  1385.             for (n = Prenum1; n > 0; --n)        /* delete the characters */
  1386.                 delchar(FALSE);
  1387.             stuffcharReadbuff('\r');
  1388.             stuffcharReadbuff(ESC);
  1389.             /*
  1390.              * Give 'r' to edit(), to get the redo command right.
  1391.              */
  1392.             command_busy = edit('r', FALSE, Prenum1);
  1393.         }
  1394.         else
  1395.         {
  1396.             prep_redo(Prenum1, NUL, 'r', c, nchar);
  1397.             while (Prenum1--)                    /* replace the characters */
  1398.             {
  1399.                 /*
  1400.                  * Replace a 'normal' character.
  1401.                  * Get ptr again, because u_save and/or showmatch() will have
  1402.                  * released the line.  At the same time we let know that the
  1403.                  * line will be changed.
  1404.                  */
  1405.                 ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
  1406.                 ptr[curwin->w_cursor.col] = nchar;
  1407.                 if (p_sm && (nchar == ')' || nchar == '}' || nchar == ']'))
  1408.                     showmatch();
  1409.                 ++curwin->w_cursor.col;
  1410.             }
  1411.             --curwin->w_cursor.col;        /* cursor on the last replaced char */
  1412.             curwin->w_set_curswant = TRUE;
  1413.             updateline();
  1414.             set_last_insert(nchar);
  1415.         }
  1416.         CHANGED;
  1417.         break;
  1418.  
  1419.       case 'J':
  1420.         if (VIsual_active)        /* join the visual lines */
  1421.             goto dooperator;
  1422.         if (checkclearop())
  1423.             break;
  1424.         if (Prenum <= 1)
  1425.             Prenum = 2;             /* default for join is two lines! */
  1426.         if (curwin->w_cursor.lnum + Prenum - 1 > curbuf->b_ml.ml_line_count)
  1427.         {
  1428.             clearopbeep();            /* beyond last line */
  1429.             break;
  1430.         }
  1431.  
  1432.         prep_redo(Prenum, NUL, 'J', NUL, NUL);
  1433.         do_do_join(Prenum, TRUE, TRUE);
  1434.         break;
  1435.  
  1436.       case 'P':
  1437.         dir = BACKWARD;
  1438.         /* FALLTHROUGH */
  1439.  
  1440.       case 'p':
  1441.         /*
  1442.          * 'P' after an operator or with Visual: Set current block.
  1443.          * 'p' after an operator or with Visual: Set current paragraph.
  1444.          */
  1445.         if (op_type != NOP || VIsual_active)
  1446.         {
  1447.             if (c == 'P')
  1448.             {
  1449.                 if (current_block('{', Prenum1) == FAIL)
  1450.                     clearopbeep();
  1451.             }
  1452.             else
  1453.             {
  1454.                 if (current_par(c, Prenum1) == FAIL)
  1455.                     clearopbeep();
  1456.             }
  1457.             curwin->w_set_curswant = TRUE;
  1458.         }
  1459.         else
  1460.         {
  1461.             prep_redo(Prenum, NUL, c, NUL, NUL);
  1462.             do_put(dir, Prenum1, FALSE);
  1463.         }
  1464.         break;
  1465.  
  1466.       case Ctrl('A'):            /* add to number */
  1467.       case Ctrl('X'):            /* subtract from number */
  1468.         if (checkclearopq())
  1469.             break;
  1470.         if (do_addsub((int)c, Prenum1) == OK)
  1471.             prep_redo(Prenum1, NUL, c, NUL, NUL);
  1472.         break;
  1473.  
  1474. /*
  1475.  * 6: Inserts
  1476.  */
  1477.       case 'A':
  1478.           type = 1;
  1479.         /* FALLTHROUGH */
  1480.  
  1481.       case 'a':
  1482.         if (op_type != NOP || VIsual_active)
  1483.         {
  1484.             if (current_word(Prenum1, type) == FAIL)
  1485.                 clearopbeep();
  1486.             curwin->w_set_curswant = TRUE;
  1487.         }
  1488.         else
  1489.         {
  1490.             if (c == 'A')
  1491.             {
  1492.                 curwin->w_set_curswant = TRUE;
  1493.                 while (oneright() == OK)
  1494.                     ;
  1495.             }
  1496.  
  1497.             /* Works just like an 'i'nsert on the next character. */
  1498.             if (u_save_cursor() == OK)
  1499.             {
  1500.                 if (!lineempty(curwin->w_cursor.lnum))
  1501.                     inc_cursor();
  1502.                 command_busy = edit(c, FALSE, Prenum1);
  1503.             }
  1504.         }
  1505.         break;
  1506.  
  1507.       case 'I':
  1508.         if (checkclearopq())
  1509.             break;
  1510.         beginline(TRUE);
  1511.         /* FALLTHROUGH */
  1512.  
  1513.       case 'i':
  1514.       case K_INS:
  1515. insert_command:
  1516.         if (checkclearopq())
  1517.             break;
  1518.         if (u_save_cursor() == OK)
  1519.             command_busy = edit(c, FALSE, Prenum1);
  1520.         break;
  1521.  
  1522.       case 'o':
  1523.           if (VIsual_active)    /* switch start and end of visual */
  1524.         {
  1525.             Prenum = VIsual.lnum;
  1526.             VIsual.lnum = curwin->w_cursor.lnum;
  1527.             curwin->w_cursor.lnum = Prenum;
  1528.             n = VIsual.col;
  1529.             VIsual.col = curwin->w_cursor.col;
  1530.             curwin->w_cursor.col = (int)n;
  1531.             curwin->w_set_curswant = TRUE;
  1532.             break;
  1533.         }
  1534.         if (checkclearop())
  1535.             break;
  1536.         if (has_format_option(FO_OPEN_COMS))
  1537.             fo_do_comments = TRUE;
  1538.         if (u_save(curwin->w_cursor.lnum,
  1539.                                 (linenr_t)(curwin->w_cursor.lnum + 1)) == OK &&
  1540.                         Opencmd(FORWARD, TRUE, FALSE))
  1541.             command_busy = edit('o', TRUE, Prenum1);
  1542.         fo_do_comments = FALSE;
  1543.         break;
  1544.  
  1545.       case 'O':
  1546.         if (checkclearopq())
  1547.             break;
  1548.         if (has_format_option(FO_OPEN_COMS))
  1549.             fo_do_comments = TRUE;
  1550.         if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
  1551.                curwin->w_cursor.lnum) == OK && Opencmd(BACKWARD, TRUE, FALSE))
  1552.             command_busy = edit('O', TRUE, Prenum1);
  1553.         fo_do_comments = FALSE;
  1554.         break;
  1555.  
  1556.       case 'R':
  1557.         if (VIsual_active)
  1558.         {
  1559.             c = 'c';
  1560.             VIsual_mode = 'V';
  1561.             goto dooperator;
  1562.         }
  1563.         if (checkclearopq())
  1564.             break;
  1565.         if (u_save_cursor() == OK)
  1566.             command_busy = edit('R', FALSE, Prenum1);
  1567.         break;
  1568.  
  1569. /*
  1570.  * 7: Operators
  1571.  */
  1572.       case '~':         /* swap case */
  1573.       /*
  1574.        * if tilde is not an operator and Visual is off: swap case
  1575.        * of a single character
  1576.        */
  1577.         if (!p_to && !VIsual_active &&
  1578.                     op_type != vim_strchr(opchars, '~') - opchars + 1)
  1579.         {
  1580.             if (checkclearopq())
  1581.                 break;
  1582.             if (lineempty(curwin->w_cursor.lnum))
  1583.             {
  1584.                 clearopbeep();
  1585.                 break;
  1586.             }
  1587.             prep_redo(Prenum, NUL, '~', NUL, NUL);
  1588.  
  1589.             if (u_save_cursor() == FAIL)
  1590.                 break;
  1591.  
  1592.             for (; Prenum1 > 0; --Prenum1)
  1593.             {
  1594.                 if (gchar_cursor() == NUL)
  1595.                     break;
  1596.                 swapchar(&curwin->w_cursor);
  1597.                 inc_cursor();
  1598.             }
  1599.  
  1600.             curwin->w_set_curswant = TRUE;
  1601.             CHANGED;
  1602.             updateline();
  1603.             break;
  1604.         }
  1605.         /*FALLTHROUGH*/
  1606.  
  1607.       case 'd':
  1608.       case 'c':
  1609.       case 'y':
  1610.       case '>':
  1611.       case '<':
  1612.       case '!':
  1613.       case '=':
  1614.       case 'Q':                    /* should start Ex mode */
  1615. dooperator:
  1616.         n = vim_strchr(opchars, c) - opchars + 1;
  1617.         if (n == op_type)        /* double operator works on lines */
  1618.             goto lineop;
  1619.         if (checkclearop())
  1620.             break;
  1621.         if (Prenum != 0)
  1622.             opnum = Prenum;
  1623.         curbuf->b_op_start = curwin->w_cursor;
  1624.         op_type = (int)n;
  1625.         break;
  1626.  
  1627. /*
  1628.  * 8: Abbreviations
  1629.  */
  1630.  
  1631.      /* when Visual the next commands are operators */
  1632.       case K_DEL:
  1633.               c = 'x';            /* DEL key behaves like 'x' */
  1634.       case 'S':
  1635.       case 'Y':
  1636.       case 'D':
  1637.       case 'C':
  1638.       case 'x':
  1639.       case 'X':
  1640.       case 's':
  1641.         /*
  1642.          * 's' or 'S' with an operator: Operate on sentence or section.
  1643.          */
  1644.         if (op_type != NOP || VIsual_active)
  1645.         {
  1646.             if (c == 's')        /* sentence */
  1647.             {
  1648.                 if (current_sent(Prenum1) == FAIL)
  1649.                     clearopbeep();
  1650.                 curwin->w_set_curswant = TRUE;
  1651.                 break;
  1652.             }
  1653.             if (c == 'S')        /* block with () */
  1654.             {
  1655.                 if (current_block('(', Prenum1) == FAIL)
  1656.                     clearopbeep();
  1657.                 curwin->w_set_curswant = TRUE;
  1658.                 break;
  1659.             }
  1660.         }
  1661.           if (VIsual_active)
  1662.         {
  1663.             static char_u trans[] = "YyDdCcxdXd";
  1664.  
  1665.                                             /* uppercase means linewise */
  1666.             if (isupper(c) && VIsual_mode != Ctrl('V'))
  1667.                 VIsual_mode = 'V';
  1668.             c = *(vim_strchr(trans, c) + 1);
  1669.             goto dooperator;
  1670.         }
  1671.  
  1672.       case '&':
  1673.         if (checkclearopq())
  1674.             break;
  1675.         if (Prenum)
  1676.             stuffnumReadbuff(Prenum);
  1677.  
  1678.         {
  1679.                 static char_u *(ar[8]) = {(char_u *)"dl", (char_u *)"dh",
  1680.                                           (char_u *)"d$", (char_u *)"c$",
  1681.                                           (char_u *)"cl", (char_u *)"cc",
  1682.                                           (char_u *)"yy", (char_u *)":s\r"};
  1683.                 static char_u *str = (char_u *)"xXDCsSY&";
  1684.  
  1685.                 stuffReadbuff(ar[(int)(vim_strchr(str, c) - str)]);
  1686.         }
  1687.         break;
  1688.  
  1689. /*
  1690.  * 9: Marks
  1691.  */
  1692.  
  1693.       case 'm':
  1694.         if (checkclearop())
  1695.             break;
  1696.         if (setmark(nchar) == FAIL)
  1697.             clearopbeep();
  1698.         break;
  1699.  
  1700.       case '\'':
  1701.         flag = TRUE;
  1702.         /* FALLTHROUGH */
  1703.  
  1704.       case '`':
  1705.         pos = getmark(nchar, (op_type == NOP));
  1706.         if (pos == (FPOS *)-1)    /* jumped to other file */
  1707.         {
  1708.             if (flag)
  1709.                 beginline(TRUE);
  1710.             break;
  1711.         }
  1712.  
  1713. cursormark:
  1714.         if (check_mark(pos) == FAIL)
  1715.             clearop();
  1716.         else
  1717.         {
  1718.             if (c == '\'' || c == '`')
  1719.                 setpcmark();
  1720.             curwin->w_cursor = *pos;
  1721.             if (flag)
  1722.                 beginline(TRUE);
  1723.         }
  1724.         op_motion_type = flag ? MLINE : MCHAR;
  1725.         op_inclusive = FALSE;        /* ignored if not MCHAR */
  1726.         curwin->w_set_curswant = TRUE;
  1727.         break;
  1728.  
  1729.     case Ctrl('O'):            /* goto older pcmark */
  1730.         Prenum1 = -Prenum1;
  1731.         /* FALLTHROUGH */
  1732.  
  1733.     case Ctrl('I'):            /* goto newer pcmark */
  1734.         if (checkclearopq())
  1735.             break;
  1736.         pos = movemark((int)Prenum1);
  1737.         if (pos == (FPOS *)-1)    /* jump to other file */
  1738.         {
  1739.             curwin->w_set_curswant = TRUE;
  1740.             break;
  1741.         }
  1742.         if (pos != NULL)    /* can jump */
  1743.             goto cursormark;
  1744.         clearopbeep();
  1745.         break;
  1746.  
  1747. /*
  1748.  * 10. Buffer setting
  1749.  */
  1750.       case '"':
  1751.         if (checkclearop())
  1752.             break;
  1753.         if (nchar != NUL && is_yank_buffer(nchar, FALSE))
  1754.         {
  1755.             yankbuffer = nchar;
  1756.             opnum = Prenum;        /* remember count before '"' */
  1757.         }
  1758.         else
  1759.             clearopbeep();
  1760.         break;
  1761.  
  1762. /*
  1763.  * 11. Visual
  1764.  */
  1765.        case 'v':
  1766.       case 'V':
  1767.       case Ctrl('V'):
  1768.         if (checkclearop())
  1769.             break;
  1770.  
  1771.             /* change Visual mode */
  1772.         if (VIsual_active)
  1773.         {
  1774.             if (VIsual_mode == c)            /* stop visual mode */
  1775.             {
  1776.                 end_visual_mode();
  1777.             }
  1778.             else                            /* toggle char/block mode */
  1779.             {                                /*     or char/line mode */
  1780.                 VIsual_mode = c;
  1781.                 showmode();
  1782.             }
  1783.             update_curbuf(NOT_VALID);        /* update the inversion */
  1784.         }
  1785.             /* start Visual mode */
  1786.         else
  1787.         {
  1788.             VIsual_save = VIsual;            /* keep for "gv" */
  1789.             VIsual_mode_save = VIsual_mode;
  1790.             start_visual_highlight();
  1791.             if (Prenum)                        /* use previously selected part */
  1792.             {
  1793.                 if (resel_VIsual_mode == NUL)    /* there is none */
  1794.                 {
  1795.                     beep_flush();
  1796.                     break;
  1797.                 }
  1798.                 VIsual = curwin->w_cursor;
  1799.                 VIsual_active = TRUE;
  1800. #ifdef USE_MOUSE
  1801.                 setmouse();
  1802. #endif
  1803.                 if (p_smd)
  1804.                     redraw_cmdline = TRUE;        /* show visual mode later */
  1805.                 /*
  1806.                  * For V and ^V, we multiply the number of lines even if there
  1807.                  * was only one -- webb
  1808.                  */
  1809.                 if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
  1810.                 {
  1811.                     curwin->w_cursor.lnum += resel_VIsual_line_count * Prenum - 1;
  1812.                     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1813.                         curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1814.                 }
  1815.                 VIsual_mode = resel_VIsual_mode;
  1816.                 if (VIsual_mode == 'v')
  1817.                 {
  1818.                     if (resel_VIsual_line_count <= 1)
  1819.                         curwin->w_cursor.col += resel_VIsual_col * Prenum - 1;
  1820.                     else
  1821.                         curwin->w_cursor.col = resel_VIsual_col;
  1822.                 }
  1823.                 if (resel_VIsual_col == MAXCOL)
  1824.                 {
  1825.                     curwin->w_curswant = MAXCOL;
  1826.                     coladvance(MAXCOL);
  1827.                 }
  1828.                 else if (VIsual_mode == Ctrl('V'))
  1829.                 {
  1830.                     curwin->w_curswant = curwin->w_virtcol +
  1831.                                             resel_VIsual_col * Prenum - 1;
  1832.                     coladvance((colnr_t)curwin->w_curswant);
  1833.                 }
  1834.                 else
  1835.                     curwin->w_set_curswant = TRUE;
  1836.                 curs_columns(TRUE);            /* recompute w_virtcol */
  1837.                 update_curbuf(NOT_VALID);    /* show the inversion */
  1838.             }
  1839.             else
  1840.             {
  1841.                 VIsual = curwin->w_cursor;
  1842.                 VIsual_mode = c;
  1843.                 VIsual_active = TRUE;
  1844. #ifdef USE_MOUSE
  1845.                 setmouse();
  1846. #endif
  1847.                 if (p_smd)
  1848.                     redraw_cmdline = TRUE;    /* show visual mode later */
  1849.                 updateline();                /* start the inversion */
  1850.             }
  1851.         }
  1852.         break;
  1853.  
  1854. /*
  1855.  * 12. Suspend
  1856.  */
  1857.  
  1858.      case Ctrl('Z'):
  1859.         clearop();
  1860.         if (VIsual_active)
  1861.             end_visual_mode();                /* stop Visual */
  1862.         stuffReadbuff((char_u *)":st\r");    /* with autowrite */
  1863.         break;
  1864.  
  1865. /*
  1866.  * 13. Window commands
  1867.  */
  1868.  
  1869.      case Ctrl('W'):
  1870.         if (checkclearop())
  1871.             break;
  1872.         do_window(nchar, Prenum);            /* everything is in window.c */
  1873.         break;
  1874.  
  1875. /*
  1876.  *   14. extended commands (starting with 'g')
  1877.  */
  1878.      case 'g':
  1879.         switch (nchar)
  1880.         {
  1881.             /*
  1882.              * "gv": reselect the previous visual area
  1883.              */
  1884.             case 'v':
  1885.                 if (checkclearop())
  1886.                     break;
  1887.                 if (VIsual_active)
  1888.                     pos = &VIsual_save;
  1889.                 else
  1890.                     pos = &VIsual;
  1891.                 if (pos->lnum == 0 || pos->lnum > curbuf->b_ml.ml_line_count ||
  1892.                                                          VIsual_end.lnum == 0)
  1893.                     beep_flush();
  1894.                 else
  1895.                 {
  1896.                     FPOS    tt;
  1897.                     int        t;
  1898.  
  1899.                     /* exchange previous and current visual area */
  1900.                     if (VIsual_active)
  1901.                     {
  1902.                         tt = VIsual;
  1903.                         VIsual = VIsual_save;
  1904.                         VIsual_save = tt;
  1905.                         t = VIsual_mode;
  1906.                         VIsual_mode = VIsual_mode_save;
  1907.                         VIsual_mode_save = t;
  1908.                         tt = curwin->w_cursor;
  1909.                     }
  1910.                     curwin->w_cursor = VIsual_end;
  1911.                     if (VIsual_active)
  1912.                         VIsual_end = tt;
  1913.                     check_cursor();
  1914.                     VIsual_active = TRUE;
  1915. #ifdef USE_MOUSE
  1916.                     setmouse();
  1917. #endif
  1918.                     update_curbuf(NOT_VALID);
  1919.                     showmode();
  1920.                 }
  1921.                 break;
  1922.  
  1923.             /*
  1924.              * "gj" and "gk" two new funny movement keys -- up and down
  1925.              * movement based on *screen* line rather than *file* line.
  1926.              */
  1927.             case 'j':
  1928.             case K_DOWN:
  1929.                 if (!curwin->w_p_wrap)
  1930.                     goto normal_j;
  1931.                 if (screengo(FORWARD, Prenum1) == FAIL)
  1932.                     clearopbeep();
  1933.                 break;
  1934.  
  1935.             case 'k':
  1936.             case K_UP:
  1937.                 if (!curwin->w_p_wrap)
  1938.                     goto normal_k;
  1939.                 if (screengo(BACKWARD, Prenum1) == FAIL)
  1940.                     clearopbeep();
  1941.                 break;
  1942.  
  1943.             /*
  1944.              * "g0", "g^" and "g$": Like "0", "^" and "$" but for screen lines.
  1945.              */
  1946.             case '^':
  1947.                 flag = TRUE;
  1948.                 /* FALLTHROUGH */
  1949.  
  1950.             case '0':
  1951.             case K_HOME:
  1952.             case K_KHOME:
  1953.                 op_motion_type = MCHAR;
  1954.                 op_inclusive = FALSE;
  1955.                 if (curwin->w_p_wrap)
  1956.                 {
  1957.                     n = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  1958.                                                            Columns) * Columns;
  1959.                     if (curwin->w_p_nu && n > 8)
  1960.                         n -= 8;
  1961.                 }
  1962.                 else
  1963.                     n = curwin->w_leftcol;
  1964.                 coladvance((colnr_t)n);
  1965.                 if (flag)
  1966.                     while (vim_iswhite(gchar_cursor()) && oneright() == OK)
  1967.                         ;
  1968.                 curwin->w_set_curswant = TRUE;
  1969.                 break;
  1970.  
  1971.             case '$':
  1972.             case K_END:
  1973.             case K_KEND:
  1974.                 op_motion_type = MCHAR;
  1975.                 op_inclusive = TRUE;
  1976.                 if (curwin->w_p_wrap)
  1977.                 {
  1978.                     curwin->w_curswant = MAXCOL;    /* so we stay at the end */
  1979.                     if (Prenum1 == 1)
  1980.                     {
  1981.                         n = ((curwin->w_virtcol + (curwin->w_p_nu ? 8 : 0)) /
  1982.                                                    Columns + 1) * Columns - 1;
  1983.                         if (curwin->w_p_nu && n > 8)
  1984.                             n -= 8;
  1985.                         coladvance((colnr_t)n);
  1986.                     }
  1987.                     else if (screengo(FORWARD, Prenum1 - 1) == FAIL)
  1988.                         clearopbeep();
  1989.                 }
  1990.                 else
  1991.                 {
  1992.                     n = curwin->w_leftcol + Columns - 1;
  1993.                     if (curwin->w_p_nu)
  1994.                         n -= 8;
  1995.                     coladvance((colnr_t)n);
  1996.                     curwin->w_set_curswant = TRUE;
  1997.                 }
  1998.                 break;
  1999.  
  2000.             /*
  2001.              * "g*" and "g#", like "*" and "#" but without using "\<" and "\>"
  2002.              */
  2003.             case '*':
  2004.             case '#':
  2005.                 goto search_word;
  2006.  
  2007.             /*
  2008.              * ge and gE: go back to end of word
  2009.              */
  2010.             case 'e':
  2011.             case 'E':
  2012.                 op_motion_type = MCHAR;
  2013.                 curwin->w_set_curswant = TRUE;
  2014.                 op_inclusive = TRUE;
  2015.                 if (bckend_word(Prenum1, nchar == 'E', FALSE) == FAIL)
  2016.                     clearopbeep();
  2017.                 break;
  2018.  
  2019.             /*
  2020.              * g CTRL-G: display info about cursor position
  2021.              */
  2022.             case Ctrl('G'):
  2023.                 cursor_pos_info();
  2024.                 break;
  2025.  
  2026.             /*
  2027.              * "gI": Start insert in column 1.
  2028.              */
  2029.             case 'I':
  2030.                 beginline(FALSE);
  2031.                 goto insert_command;
  2032.  
  2033.             /*
  2034.              * "gf": goto file, edit file under cursor
  2035.              * "]f" and "[f": can also be used.
  2036.              */
  2037.             case 'f':
  2038. gotofile:
  2039.                 ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP);
  2040.                 if (ptr != NULL)
  2041.                 {
  2042.                     /* do autowrite if necessary */
  2043.                     if (curbuf->b_changed && curbuf->b_nwindows <= 1 && !p_hid)
  2044.                         autowrite(curbuf, FALSE);
  2045.                     setpcmark();
  2046.                     (void)do_ecmd(0, ptr, NULL, NULL, (linenr_t)0,
  2047.                                                        p_hid ? ECMD_HIDE : 0);
  2048.                     vim_free(ptr);
  2049.                 }
  2050.                 else
  2051.                     clearop();
  2052.                 break;
  2053.  
  2054.             /*
  2055.              * "gs": Goto sleep, but keep on checking for CTRL-C
  2056.              */
  2057.             case 's':
  2058.                 while (Prenum1-- && !got_int)
  2059.                 {
  2060.                     mch_delay(1000L, TRUE);
  2061.                     mch_breakcheck();
  2062.                 }
  2063.                 break;
  2064.  
  2065.             /*
  2066.              * "ga": Display the ascii value of the character under the
  2067.              * cursor.  It is displayed in decimal, hex, and octal. -- webb
  2068.              */
  2069.             case 'a':
  2070.                 do_ascii();
  2071.                 break;
  2072.  
  2073.             /*
  2074.              * "gg": Goto the first line in file.  With a count it goes to
  2075.              * that line number like for G. -- webb
  2076.              */
  2077.             case 'g':
  2078. goto_line_one:
  2079.                 if (Prenum == 0)
  2080.                     Prenum = 1;
  2081.                 goto goto_line;
  2082.  
  2083.             /*
  2084.              * Operater to format text:
  2085.              *   gq        same as 'Q' operator.
  2086.              * Operators to change the case of text:
  2087.              *   g~        Toggle the case of the text.
  2088.              *   gu        Change text to lower case.
  2089.              *   gU        Change text to upper case.
  2090.              *                                    --webb
  2091.              */
  2092.             case 'q':
  2093.             case '~':
  2094.             case 'u':
  2095.             case 'U':
  2096.                 prechar = c;
  2097.                 c = nchar;
  2098.                 goto dooperator;
  2099.  
  2100.         /*
  2101.          * "gd": Find first occurence of pattern under the cursor in the
  2102.          *       current function
  2103.          * "gD": idem, but in the current file.
  2104.          */
  2105.             case 'd':
  2106.             case 'D':
  2107.                 do_gd(nchar);
  2108.                 break;
  2109.  
  2110. #ifdef USE_MOUSE
  2111.             /*
  2112.              * g<*Mouse> : <C-*mouse>
  2113.              */
  2114.             case K_MIDDLEMOUSE:
  2115.             case K_MIDDLEDRAG:
  2116.             case K_MIDDLERELEASE:
  2117.             case K_LEFTMOUSE:
  2118.             case K_LEFTDRAG:
  2119.             case K_LEFTRELEASE:
  2120.             case K_RIGHTMOUSE:
  2121.             case K_RIGHTDRAG:
  2122.             case K_RIGHTRELEASE:
  2123.                 mod_mask = MOD_MASK_CTRL;
  2124.                 (void)do_mouse(nchar, BACKWARD, Prenum1, FALSE);
  2125.                 break;
  2126.  
  2127.             case K_IGNORE:
  2128.                 break;
  2129. #endif
  2130.  
  2131.             default:
  2132.                 clearopbeep();
  2133.                 break;
  2134.         }
  2135.         break;
  2136.  
  2137. /*
  2138.  * 15. mouse click
  2139.  */
  2140. #ifdef USE_MOUSE
  2141.       case K_MIDDLEMOUSE:
  2142.       case K_MIDDLEDRAG:
  2143.       case K_MIDDLERELEASE:
  2144.       case K_LEFTMOUSE:
  2145.       case K_LEFTDRAG:
  2146.       case K_LEFTRELEASE:
  2147.       case K_RIGHTMOUSE:
  2148.       case K_RIGHTDRAG:
  2149.       case K_RIGHTRELEASE:
  2150.         (void)do_mouse(c, BACKWARD, Prenum1, FALSE);
  2151.         break;
  2152.  
  2153.       case K_IGNORE:
  2154.         break;
  2155. #endif
  2156.  
  2157. #ifdef USE_GUI
  2158. /*
  2159.  * 16. scrollbar movement
  2160.  */
  2161.       case K_SCROLLBAR:
  2162.         if (op_type != NOP)
  2163.             clearopbeep();
  2164.  
  2165.         /* Even if an operator was pending, we still want to scroll */
  2166.         gui_do_scroll();
  2167.         break;
  2168.  
  2169.       case K_HORIZ_SCROLLBAR:
  2170.         if (op_type != NOP)
  2171.             clearopbeep();
  2172.  
  2173.         /* Even if an operator was pending, we still want to scroll */
  2174.         gui_do_horiz_scroll();
  2175.         break;
  2176. #endif
  2177.  
  2178. /*
  2179.  * 17. The end
  2180.  */
  2181.       case ESC:
  2182.         /* Don't drop through and beep if we are canceling a command: */
  2183.         if (!VIsual_active && (op_type != NOP ||
  2184.                                                opnum || Prenum || yankbuffer))
  2185.         {
  2186.             clearop();                    /* don't beep */
  2187.             break;
  2188.         }
  2189.         if (VIsual_active)
  2190.         {
  2191.             end_visual_mode();            /* stop Visual */
  2192.             update_curbuf(NOT_VALID);
  2193.             clearop();                    /* don't beep */
  2194.             break;
  2195.         }
  2196.         /* ESC in normal mode: beep, but don't flush buffers */
  2197.         clearop();
  2198.         vim_beep();
  2199.         break;
  2200.  
  2201.       default:                    /* not a known command */
  2202.         clearopbeep();
  2203.         break;
  2204.  
  2205.     }    /* end of switch on command character */
  2206.  
  2207. /*
  2208.  * if we didn't start or finish an operator, reset yankbuffer, unless we
  2209.  * need it later.
  2210.  */
  2211.     if (!finish_op && !op_type && vim_strchr((char_u *)"\"DCYSsXx.", c) == NULL)
  2212.         yankbuffer = 0;
  2213.  
  2214. /*
  2215.  * If an operation is pending, handle it...
  2216.  */
  2217.     do_pending_operator(c, nchar, finish_op, searchbuff, 
  2218.                       &command_busy, old_col, FALSE, dont_adjust_op_end);
  2219.  
  2220.     /*
  2221.      * Wait when a message is displayed that will be overwritten by the mode
  2222.      * message.
  2223.      * In Visual mode and with "^O" in Insert mode, a short message will be
  2224.      * overwritten by the mode message.  Wait a bit, until a key is hit.
  2225.      * In Visual mode, it's more important to keep the Visual area updated
  2226.      * than keeping a message (e.g. from a /pat search).
  2227.      * Only do this if the command was typed, not from a mapping.
  2228.      * Also wait a bit after an error message, e.g. for "^O:".
  2229.      * Don't redraw the screen, it would remove the message.
  2230.      */
  2231.     if (((p_smd && ((VIsual_active && old_pos.lnum == curwin->w_cursor.lnum &&
  2232.             old_pos.col == curwin->w_cursor.col) || restart_edit) &&
  2233.             (clear_cmdline || redraw_cmdline) && msg_didany && KeyTyped) ||
  2234.             (restart_edit && !VIsual_active && (msg_scroll || emsg_on_display
  2235. #ifdef SLEEP_IN_EMSG
  2236.                                         || need_sleep
  2237. #endif
  2238.                                                         ))) &&
  2239.             yankbuffer == 0 && !command_busy && stuff_empty() && op_type == NOP)
  2240.     {
  2241.         ++RedrawingDisabled;
  2242.         cursupdate();
  2243.         --RedrawingDisabled;
  2244.         setcursor();
  2245.         flushbuf();
  2246.         if (msg_scroll || emsg_on_display
  2247. #ifdef SLEEP_IN_EMSG
  2248.                                             || need_sleep
  2249. #endif
  2250.                                                             )
  2251.             mch_delay(1000L, TRUE);        /* wait at least one second */
  2252.         mch_delay(10000L, FALSE);        /* wait up to ten seconds */
  2253.  
  2254.         msg_scroll = FALSE;
  2255.         emsg_on_display = FALSE;
  2256. #ifdef SLEEP_IN_EMSG
  2257.         need_sleep = FALSE;
  2258. #endif
  2259.     }
  2260.  
  2261. normal_end:
  2262.     if (op_type == NOP && yankbuffer == 0)
  2263.         clear_showcmd();
  2264.  
  2265.     if (restart_edit && op_type == NOP && !VIsual_active
  2266.                          && !command_busy && stuff_empty() && yankbuffer == 0)
  2267.         (void)edit(restart_edit, FALSE, 1L);
  2268.  
  2269.     if (!search_dont_set_mark)
  2270.         checkpcmark();            /* check if we moved since setting pcmark */
  2271.     vim_free(searchbuff);
  2272.  
  2273. /*
  2274.  * Update the other windows for the current buffer if modified has been set in
  2275.  * set_Changed() (This should be done more efficiently)
  2276.  */
  2277.     if (modified)
  2278.     {
  2279.         WIN        *wp;
  2280.  
  2281.         for (wp = firstwin; wp; wp = wp->w_next)
  2282.             if (wp != curwin && wp->w_buffer == curbuf)
  2283.             {
  2284.                 cursor_off();
  2285.                 wp->w_redr_type = NOT_VALID;
  2286.                 /*
  2287.                  * don't do the actual redraw if wait_return() has just been
  2288.                  * called and the user typed a ":"
  2289.                  */
  2290.                 if (!skip_redraw)
  2291.                     win_update(wp);
  2292.             }
  2293.         modified = FALSE;
  2294.     }
  2295. }
  2296.  
  2297. /*
  2298.  * Handle an operator after visual mode or when the movement is finished
  2299.  */
  2300.     void
  2301. do_pending_operator(c, nchar, finish_op, searchbuff, command_busy,
  2302.                                         old_col, gui_yank, dont_adjust_op_end)
  2303.     register int    c;
  2304.     int                nchar;
  2305.     int                finish_op;
  2306.     char_u            *searchbuff;
  2307.     int                *command_busy;
  2308.     int                old_col;
  2309.     int                gui_yank;        /* yanking visual area for GUI */
  2310.     int                dont_adjust_op_end;
  2311. {
  2312.     /* The visual area is remembered for redo */
  2313.     static int        redo_VIsual_mode = NUL;    /* 'v', 'V', or Ctrl-V */
  2314.     static linenr_t    redo_VIsual_line_count;        /* number of lines */
  2315.     static colnr_t    redo_VIsual_col;        /* number of cols or end column */
  2316.     static long        redo_VIsual_Prenum;        /* Prenum for operator */
  2317.  
  2318.     linenr_t        Prenum1 = 1L;
  2319.     FPOS            old_cursor;
  2320.     int                VIsual_was_active = VIsual_active;
  2321.     int                redraw;
  2322.  
  2323. #ifdef USE_GUI
  2324.     /*
  2325.      * Yank the visual area into the GUI selection register before we operate
  2326.      * on it and lose it forever.  This could call do_pending_operator()
  2327.      * recursively, but that's OK because gui_yank will be TRUE for the
  2328.      * nested call.  Note also that we call gui_copy_selection() and not
  2329.      * gui_auto_select().  This is because even when 'autoselect' is not set,
  2330.      * if we operate on the text, eg by deleting it, then this is considered to
  2331.      * be an explicit request for it to be put in the global cut buffer, so we
  2332.      * always want to do it here. -- webb
  2333.      */
  2334.     if (gui.in_use && op_type != NOP && !gui_yank && VIsual_active
  2335.                                                          && !redo_VIsual_busy)
  2336.         gui_copy_selection();
  2337. #endif
  2338.     old_cursor = curwin->w_cursor;
  2339.  
  2340.     /*
  2341.      * If an operation is pending, handle it...
  2342.      */
  2343.     if ((VIsual_active || finish_op) && op_type != NOP)
  2344.     {
  2345.         op_is_VIsual = VIsual_active;
  2346.         if (op_type != YANK && !VIsual_active)        /* can't redo yank */
  2347.         {
  2348.             prep_redo(Prenum, prechar, opchars[op_type - 1], c, nchar);
  2349.             if (c == '/' || c == '?')                /* was a search */
  2350.             {
  2351.                 /*
  2352.                  * If 'cpoptions' does not contain 'r', insert the search
  2353.                  * pattern to really repeat the same command.
  2354.                  */
  2355.                 if (vim_strchr(p_cpo, CPO_REDO) == NULL)
  2356.                     AppendToRedobuff(searchbuff);
  2357.                 AppendToRedobuff(NL_STR);
  2358.             }
  2359.         }
  2360.  
  2361.         if (redo_VIsual_busy)
  2362.         {
  2363.             curbuf->b_op_start = curwin->w_cursor;
  2364.             curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
  2365.             if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  2366.                 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2367.             VIsual_mode = redo_VIsual_mode;
  2368.             if (VIsual_mode == 'v')
  2369.             {
  2370.                 if (redo_VIsual_line_count <= 1)
  2371.                     curwin->w_cursor.col += redo_VIsual_col - 1;
  2372.                 else
  2373.                     curwin->w_cursor.col = redo_VIsual_col;
  2374.             }
  2375.             if (redo_VIsual_col == MAXCOL)
  2376.             {
  2377.                 curwin->w_curswant = MAXCOL;
  2378.                 coladvance(MAXCOL);
  2379.             }
  2380.             Prenum = redo_VIsual_Prenum;
  2381.         }
  2382.         else if (VIsual_active)
  2383.         {
  2384.             curbuf->b_op_start = VIsual;
  2385.             VIsual_end = curwin->w_cursor;
  2386.             if (VIsual_mode == 'V')
  2387.                 curbuf->b_op_start.col = 0;
  2388.         }
  2389.  
  2390.         /*
  2391.          * Set b_op_start to the first position of the operated text, b_op_end
  2392.          * to the end of the operated text.  w_cursor is equal to b_op_start.
  2393.          */
  2394.         if (lt(curbuf->b_op_start, curwin->w_cursor))
  2395.         {
  2396.             curbuf->b_op_end = curwin->w_cursor;
  2397.             curwin->w_cursor = curbuf->b_op_start;
  2398.         }
  2399.         else
  2400.         {
  2401.             curbuf->b_op_end = curbuf->b_op_start;
  2402.             curbuf->b_op_start = curwin->w_cursor;
  2403.         }
  2404.         op_line_count = curbuf->b_op_end.lnum - curbuf->b_op_start.lnum + 1;
  2405.  
  2406.         if (VIsual_active || redo_VIsual_busy)
  2407.         {
  2408.             if (VIsual_mode == Ctrl('V'))        /* block mode */
  2409.             {
  2410.                 colnr_t        start, end;
  2411.  
  2412.                 op_block_mode = TRUE;
  2413.  
  2414.                 getvcol(curwin, &(curbuf->b_op_start),
  2415.                                           &op_start_vcol, NULL, &op_end_vcol);
  2416.                 if (!redo_VIsual_busy)
  2417.                 {
  2418.                     getvcol(curwin, &(curbuf->b_op_end), &start, NULL, &end);
  2419.                     if (start < op_start_vcol)
  2420.                         op_start_vcol = start;
  2421.                     if (end > op_end_vcol)
  2422.                         op_end_vcol = end;
  2423.                 }
  2424.  
  2425.                 /* if '$' was used, get op_end_vcol from longest line */
  2426.                 if (curwin->w_curswant == MAXCOL)
  2427.                 {
  2428.                     curwin->w_cursor.col = MAXCOL;
  2429.                     op_end_vcol = 0;
  2430.                     for (curwin->w_cursor.lnum = curbuf->b_op_start.lnum;
  2431.                             curwin->w_cursor.lnum <= curbuf->b_op_end.lnum;
  2432.                             ++curwin->w_cursor.lnum)
  2433.                     {
  2434.                         getvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
  2435.                         if (end > op_end_vcol)
  2436.                             op_end_vcol = end;
  2437.                     }
  2438.                 }
  2439.                 else if (redo_VIsual_busy)
  2440.                     op_end_vcol = op_start_vcol + redo_VIsual_col - 1;
  2441.                 /*
  2442.                  * Correct b_op_end.col and b_op_start.col to be the
  2443.                  * upper-left and lower-right corner of the block area.
  2444.                  */
  2445.                 curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
  2446.                 coladvance(op_end_vcol);
  2447.                 curbuf->b_op_end = curwin->w_cursor;
  2448.                 curwin->w_cursor = curbuf->b_op_start;
  2449.                 coladvance(op_start_vcol);
  2450.                 curbuf->b_op_start = curwin->w_cursor;
  2451.             }
  2452.  
  2453.             if (!redo_VIsual_busy)
  2454.             {
  2455.                 /*
  2456.                  * Prepare to reselect and redo Visual: this is based on the
  2457.                  * size of the Visual text
  2458.                  */
  2459.                 resel_VIsual_mode = VIsual_mode;
  2460.                 if (curwin->w_curswant == MAXCOL)
  2461.                     resel_VIsual_col = MAXCOL;
  2462.                 else if (VIsual_mode == Ctrl('V'))
  2463.                     resel_VIsual_col = op_end_vcol - op_start_vcol + 1;
  2464.                 else if (op_line_count > 1)
  2465.                     resel_VIsual_col = curbuf->b_op_end.col;
  2466.                 else
  2467.                     resel_VIsual_col = curbuf->b_op_end.col -
  2468.                                                 curbuf->b_op_start.col + 1;
  2469.                 resel_VIsual_line_count = op_line_count;
  2470.             }
  2471.                                                 /* can't redo yank and : */
  2472.             if (op_type != YANK && op_type != COLON)
  2473.             {
  2474.                 prep_redo(0L, NUL, 'v', prechar, opchars[op_type - 1]);
  2475.                 redo_VIsual_mode = resel_VIsual_mode;
  2476.                 redo_VIsual_col = resel_VIsual_col;
  2477.                 redo_VIsual_line_count = resel_VIsual_line_count;
  2478.                 redo_VIsual_Prenum = Prenum;
  2479.             }
  2480.  
  2481.             /*
  2482.              * Mincl defaults to TRUE.
  2483.              * If op_end is on a NUL (empty line) op_inclusive becomes FALSE
  2484.              * This makes "d}P" and "v}dP" work the same.
  2485.              */
  2486.             op_inclusive = TRUE;
  2487.             if (VIsual_mode == 'V')
  2488.                 op_motion_type = MLINE;
  2489.             else
  2490.             {
  2491.                 op_motion_type = MCHAR;
  2492.                 if (*ml_get_pos(&(curbuf->b_op_end)) == NUL)
  2493.                     op_inclusive = FALSE;
  2494.             }
  2495.  
  2496.             redo_VIsual_busy = FALSE;
  2497.             /*
  2498.              * Switch Visual off now, so screen updating does
  2499.              * not show inverted text when the screen is redrawn.
  2500.              * With YANK and sometimes with COLON and FILTER there is no screen
  2501.              * redraw, so it is done here to remove the inverted part.
  2502.              */
  2503.             if (!gui_yank)
  2504.             {
  2505.                 VIsual_active = FALSE;
  2506. #ifdef USE_MOUSE
  2507.                 setmouse();
  2508. #endif
  2509.                 if (p_smd)
  2510.                     clear_cmdline = TRUE;    /* unshow visual mode later */
  2511.                 if (op_type == YANK || op_type == COLON || op_type == FILTER)
  2512.                     update_curbuf(NOT_VALID);
  2513.             }
  2514.  
  2515.             /* set Prenum1 for LSHIFT and RSHIFT, e.g. "V3j2>" */
  2516.             if (Prenum == 0)
  2517.                 Prenum1 = 1L;
  2518.             else
  2519.                 Prenum1 = Prenum;
  2520.         }
  2521.  
  2522.         curwin->w_set_curswant = TRUE;
  2523.  
  2524.             /* op_empty is set when start and end are the same */
  2525.         op_empty = (op_motion_type == MCHAR && !op_inclusive &&
  2526.                                  equal(curbuf->b_op_start, curbuf->b_op_end));
  2527.  
  2528.     /*
  2529.      * If the end of an operator is in column one while op_motion_type is
  2530.      * MCHAR and op_inclusive is FALSE, we put op_end after the last character
  2531.      * in the previous line. If op_start is on or before the first non-blank
  2532.      * in the line, the operator becomes linewise (strange, but that's the way
  2533.      * vi does it).
  2534.      */
  2535.         if (op_motion_type == MCHAR && op_inclusive == FALSE &&
  2536.                            !dont_adjust_op_end && curbuf->b_op_end.col == 0 &&
  2537.                                                             op_line_count > 1)
  2538.         {
  2539.             op_end_adjusted = TRUE;        /* remember that we did this */
  2540.             --op_line_count;
  2541.             --curbuf->b_op_end.lnum;
  2542.             if (inindent(0))
  2543.                 op_motion_type = MLINE;
  2544.             else
  2545.             {
  2546.                 curbuf->b_op_end.col = STRLEN(ml_get(curbuf->b_op_end.lnum));
  2547.                 if (curbuf->b_op_end.col)
  2548.                 {
  2549.                     --curbuf->b_op_end.col;
  2550.                     op_inclusive = TRUE;
  2551.                 }
  2552.             }
  2553.         }
  2554.         else
  2555.             op_end_adjusted = FALSE;
  2556.         switch (op_type)
  2557.         {
  2558.           case LSHIFT:
  2559.           case RSHIFT:
  2560.             do_shift(op_type, TRUE, (int)Prenum1);
  2561.             break;
  2562.  
  2563.           case JOIN:
  2564.             if (op_line_count < 2)
  2565.                 op_line_count = 2;
  2566.             if (curwin->w_cursor.lnum + op_line_count - 1 >
  2567.                                                    curbuf->b_ml.ml_line_count)
  2568.                 beep_flush();
  2569.             else
  2570.             {
  2571.                 /*
  2572.                  * If the cursor position has been changed, recompute the
  2573.                  * current cursor position in the window. If it's not visible,
  2574.                  * don't keep the window updated when joining the lines.
  2575.                  */
  2576.                 if (old_cursor.lnum != curwin->w_cursor.lnum ||
  2577.                                        old_cursor.col != curwin->w_cursor.col)
  2578.                     redraw = (curs_rows() == OK);
  2579.                 else
  2580.                     redraw = TRUE;
  2581.                 do_do_join(op_line_count, TRUE, redraw);
  2582.             }
  2583.             break;
  2584.  
  2585.           case DELETE:
  2586.             if (!op_empty)
  2587.                 do_delete();
  2588.             break;
  2589.  
  2590.           case YANK:
  2591.             if (!op_empty)
  2592.                 (void)do_yank(FALSE, !gui_yank);
  2593.             break;
  2594.  
  2595.           case CHANGE:
  2596.             *command_busy = do_change();    /* will set op_type to NOP */
  2597.             break;
  2598.  
  2599.           case FILTER:
  2600.             if (vim_strchr(p_cpo, CPO_FILTER) != NULL)
  2601.                 AppendToRedobuff((char_u *)"!\r");    /* use any last used !cmd */
  2602.             else
  2603.                 bangredo = TRUE;    /* do_bang() will put cmd in redo buffer */
  2604.  
  2605.           case INDENT:
  2606.           case COLON:
  2607.  
  2608. #if defined(LISPINDENT) || defined(CINDENT)
  2609.             /*
  2610.              * If 'equalprg' is empty, do the indenting internally.
  2611.              */
  2612.             if (op_type == INDENT && *p_ep == NUL)
  2613.             {
  2614. # ifdef LISPINDENT
  2615.                 if (curbuf->b_p_lisp)
  2616.                 {
  2617.                     do_reindent(get_lisp_indent);
  2618.                     break;
  2619.                 }
  2620. # endif
  2621. # ifdef CINDENT
  2622.                 do_reindent(get_c_indent);
  2623.                 break;
  2624. # endif
  2625.             }
  2626. #endif /* defined(LISPINDENT) || defined(CINDENT) */
  2627.  
  2628. dofilter:
  2629.             if (VIsual_was_active)
  2630.                 sprintf((char *)IObuff, ":'<,'>");
  2631.             else
  2632.                 sprintf((char *)IObuff, ":%ld,%ld",
  2633.                         (long)curbuf->b_op_start.lnum,
  2634.                         (long)curbuf->b_op_end.lnum);
  2635.             stuffReadbuff(IObuff);
  2636.             if (op_type != COLON)
  2637.                 stuffReadbuff((char_u *)"!");
  2638.             if (op_type == INDENT)
  2639.             {
  2640. #ifndef CINDENT
  2641.                 if (*p_ep == NUL)
  2642.                     stuffReadbuff((char_u *)"indent");
  2643.                 else
  2644. #endif
  2645.                     stuffReadbuff(p_ep);
  2646.                 stuffReadbuff((char_u *)"\n");
  2647.             }
  2648.             else if (op_type == FORMAT || op_type == GFORMAT)
  2649.             {
  2650.                 if (*p_fp == NUL)
  2651.                     stuffReadbuff((char_u *)"fmt");
  2652.                 else
  2653.                     stuffReadbuff(p_fp);
  2654.                 stuffReadbuff((char_u *)"\n");
  2655.             }
  2656.                 /*    do_cmdline() does the rest */
  2657.             break;
  2658.  
  2659.           case TILDE:
  2660.           case UPPER:
  2661.           case LOWER:
  2662.             if (!op_empty)
  2663.                 do_tilde();
  2664.             break;
  2665.  
  2666.           case FORMAT:
  2667.           case GFORMAT:
  2668.             if (*p_fp != NUL)
  2669.                 goto dofilter;        /* use external command */
  2670.             do_format();            /* use internal function */
  2671.             break;
  2672.  
  2673.           default:
  2674.             clearopbeep();
  2675.         }
  2676.         prechar = NUL;
  2677.         if (!gui_yank)
  2678.         {
  2679.             /*
  2680.              * if 'sol' not set, go back to old column for some commands
  2681.              */
  2682.             if (!p_sol && op_motion_type == MLINE && (op_type == LSHIFT ||
  2683.                                     op_type == RSHIFT || op_type == DELETE))
  2684.                 coladvance(curwin->w_curswant = old_col);
  2685.             op_type = NOP;
  2686.         }
  2687.         else
  2688.             curwin->w_cursor = old_cursor;
  2689.         op_block_mode = FALSE;
  2690.         yankbuffer = 0;
  2691.     }
  2692. }
  2693.  
  2694. #ifdef USE_MOUSE
  2695. /*
  2696.  * Do the appropriate action for the current mouse click in the current mode.
  2697.  *
  2698.  * Normal Mode:
  2699.  * event         modi-  position      visual       change    action
  2700.  *               fier   cursor                         window
  2701.  * left press      -        yes            end                yes
  2702.  * left press      C        yes            end                yes        "^]" (2)
  2703.  * left press      S        yes            end                yes        "*" (2)
  2704.  * left drag      -        yes        start if moved      no
  2705.  * left relse      -        yes        start if moved        no
  2706.  * middle press      -      yes         if not active        no        put register
  2707.  * middle press      -     yes         if active            no        yank and put
  2708.  * right press      -        yes        start or extend        yes
  2709.  * right press      S        yes        no change              yes        "#" (2)
  2710.  * right drag      -        yes        extend                no
  2711.  * right relse      -        yes        extend                no
  2712.  *
  2713.  * Insert or Replace Mode:
  2714.  * event         modi-  position      visual       change    action
  2715.  *               fier   cursor                         window
  2716.  * left press      -        yes        (cannot be active)    yes
  2717.  * left press      C        yes        (cannot be active)    yes        "CTRL-O^]" (2)
  2718.  * left press      S        yes        (cannot be active)    yes        "CTRL-O*" (2)
  2719.  * left drag      -        yes        start or extend (1)    no        CTRL-O (1)
  2720.  * left relse      -        yes        start or extend (1)    no        CTRL-O (1)
  2721.  * middle press      -     no          (cannot be active)    no        put register
  2722.  * right press      -        yes        start or extend        yes        CTRL-O
  2723.  * right press      S        yes        (cannot be active)    yes        "CTRL-O#" (2)
  2724.  *
  2725.  * (1) only if mouse pointer moved since press
  2726.  * (2) only if click is in same buffer
  2727.  *
  2728.  * Return TRUE if start_arrow() should be called for edit mode.
  2729.  */
  2730.     int
  2731. do_mouse(c, dir, count, fix_indent)
  2732.     int        c;                /* K_LEFTMOUSE, etc */
  2733.     int        dir;            /* Direction to 'put' if necessary */
  2734.     long    count;
  2735.     int        fix_indent;        /* Do we fix indent for 'put' if necessary? */
  2736. {
  2737.     static int    ignore_drag_release = FALSE;
  2738.     static FPOS    orig_cursor;
  2739.     static int    do_always = FALSE;        /* ignore 'mouse' setting next time */
  2740.     static int    got_click = FALSE;        /* got a click some time back */
  2741.  
  2742.     int        which_button;        /* MOUSE_LEFT, _MIDDLE or _RIGHT */
  2743.     int        is_click;            /* If FALSE it's a drag or release event */
  2744.     int        is_drag;            /* If TRUE it's a drag event */
  2745.     int        jump_flags = 0;        /* flags for jump_to_mouse() */
  2746.     FPOS    start_visual;
  2747.     FPOS    end_visual;
  2748.     BUF        *save_buffer;
  2749.     int        diff;
  2750.     int        moved;                /* Has cursor moved? */
  2751.     int        c1, c2;
  2752.     int        VIsual_was_active = VIsual_active;
  2753.  
  2754.     /*
  2755.      * When GUI is active, always recognize mouse events, otherwise:
  2756.      * - Ignore mouse event in normal mode if 'mouse' doesn't include 'n'.
  2757.      * - Ignore mouse event in visual mode if 'mouse' doesn't include 'v'.
  2758.      * - For command line and insert mode 'mouse' is checked before calling
  2759.      *   do_mouse().
  2760.      */
  2761.     if (do_always)
  2762.         do_always = FALSE;
  2763.     else
  2764. #ifdef USE_GUI
  2765.         if (!gui.in_use)
  2766. #endif
  2767.         {
  2768.             if (VIsual_active)
  2769.             {
  2770.                 if (!mouse_has(MOUSE_VISUAL))
  2771.                     return FALSE;
  2772.             }
  2773.             else if (State == NORMAL && !mouse_has(MOUSE_NORMAL))
  2774.                 return FALSE;
  2775.         }
  2776.  
  2777.     which_button = get_mouse_button(KEY2TERMCAP1(c), &is_click, &is_drag);
  2778.  
  2779.     /*
  2780.      * Ignore drag and release events if we didn't get a click.
  2781.      */
  2782.     if (is_click)
  2783.         got_click = TRUE;
  2784.     else
  2785.     {
  2786.         if (!got_click)                    /* didn't get click, ignore */
  2787.             return FALSE;
  2788.         if (!is_drag)                    /* release, reset got_click */
  2789.             got_click = FALSE;
  2790.     }
  2791.  
  2792.     /*
  2793.      * ALT is currently ignored
  2794.      */
  2795.     if ((mod_mask & MOD_MASK_ALT))
  2796.         return FALSE;
  2797.  
  2798.     /*
  2799.      * CTRL right mouse button does CTRL-T
  2800.      */
  2801.     if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT)
  2802.     {
  2803.         if (State & INSERT)
  2804.             stuffcharReadbuff(Ctrl('O'));
  2805.         stuffcharReadbuff(Ctrl('T'));
  2806.         got_click = FALSE;                /* ignore drag&release now */
  2807.         return FALSE;
  2808.     }
  2809.  
  2810.     /*
  2811.      * CTRL only works with left mouse button
  2812.      */
  2813.     if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
  2814.         return FALSE;
  2815.  
  2816.     /*
  2817.      * When a modifier is down, ignore drag and release events, as well as
  2818.      * multiple clicks and the middle mouse button. 
  2819.      */
  2820.     if ((mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL | MOD_MASK_ALT)) &&
  2821.                             (!is_click || (mod_mask & MOD_MASK_MULTI_CLICK) ||
  2822.                                                 which_button == MOUSE_MIDDLE))
  2823.         return FALSE;
  2824.  
  2825.     /*
  2826.      * If the button press was used as the movement command for an operator
  2827.      * (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
  2828.      * drag/release events.
  2829.      */
  2830.     if (!is_click && (ignore_drag_release || which_button == MOUSE_MIDDLE))
  2831.         return FALSE;
  2832.  
  2833.     /*
  2834.      * Middle mouse button does a 'put' of the selected text
  2835.      */
  2836.     if (which_button == MOUSE_MIDDLE)
  2837.     {
  2838.         if (State == NORMAL)
  2839.         {
  2840.             /*
  2841.              * If an operator was pending, we don't know what the user wanted
  2842.              * to do. Go back to normal mode: Clear the operator and beep().
  2843.              */
  2844.             if (op_type != NOP)
  2845.             {
  2846.                 clearopbeep();
  2847.                 return FALSE;
  2848.             }
  2849.  
  2850.             /*
  2851.              * If visual was active, yank the highlighted text and put it
  2852.              * before the mouse pointer position.
  2853.              */
  2854.             if (VIsual_active)
  2855.             {
  2856.                 stuffcharReadbuff('y');
  2857.                 stuffcharReadbuff(K_MIDDLEMOUSE);
  2858.                 do_always = TRUE;        /* ignore 'mouse' setting next time */
  2859.                 return FALSE;
  2860.             }
  2861.             /*
  2862.              * The rest is below jump_to_mouse()
  2863.              */
  2864.         }
  2865.  
  2866.         /*
  2867.          * Middle click in insert mode doesn't move the mouse, just insert the
  2868.          * contents of a register.  '.' register is special, can't insert that
  2869.          * with do_put().
  2870.          */
  2871.         else if (State & INSERT)
  2872.         {
  2873.             if (yankbuffer == '.')
  2874.                 insertbuf(yankbuffer);
  2875.             else
  2876.             {
  2877. #ifdef USE_GUI
  2878.                 if (gui.in_use && yankbuffer == 0)
  2879.                     yankbuffer = '*';
  2880. #endif
  2881.                 do_put(BACKWARD, 1L, fix_indent);
  2882.  
  2883.                 /* Put cursor after the end of the just pasted text. */
  2884.                 curwin->w_cursor = curbuf->b_op_end;
  2885.                 if (gchar_cursor() != NUL)
  2886.                     ++curwin->w_cursor.col;
  2887.  
  2888.                 /* Repeat it with CTRL-R x, not exactly the same, but mostly
  2889.                  * works fine. */
  2890.                 AppendCharToRedobuff(Ctrl('R'));
  2891.                 if (yankbuffer == 0)
  2892.                     AppendCharToRedobuff('"');
  2893.                 else
  2894.                     AppendCharToRedobuff(yankbuffer);
  2895.             }
  2896.             return FALSE;
  2897.         }
  2898.         else
  2899.             return FALSE;
  2900.     }
  2901.  
  2902.     if (!is_click)
  2903.         jump_flags |= MOUSE_FOCUS;
  2904.  
  2905.     start_visual.lnum = 0;
  2906.  
  2907.     if ((State & (NORMAL | INSERT)) &&
  2908.                                !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
  2909.     {
  2910.         if (which_button == MOUSE_LEFT)
  2911.         {
  2912.             if (is_click)
  2913.             {
  2914.                 if (VIsual_active)
  2915.                 {
  2916.                     end_visual_mode();
  2917.                     update_curbuf(NOT_VALID);
  2918.                 }
  2919.             }
  2920.             else
  2921.                 jump_flags |= MOUSE_MAY_VIS;
  2922.         }
  2923.         else if (which_button == MOUSE_RIGHT)
  2924.         {
  2925.             if (is_click && VIsual_active)
  2926.             {
  2927.                 /*
  2928.                  * Remember the start and end of visual before moving the
  2929.                  * cursor.
  2930.                  */
  2931.                 if (lt(curwin->w_cursor, VIsual))
  2932.                 {
  2933.                     start_visual = curwin->w_cursor;
  2934.                     end_visual = VIsual;
  2935.                 }
  2936.                 else
  2937.                 {
  2938.                     start_visual = VIsual;
  2939.                     end_visual = curwin->w_cursor;
  2940.                 }
  2941.             }
  2942.             jump_flags |= MOUSE_MAY_VIS;
  2943.         }
  2944.     }
  2945.  
  2946.     if (!is_drag)
  2947.     {
  2948.         /*
  2949.          * If an operator is pending, ignore all drags and releases until the
  2950.          * next mouse click.
  2951.          */
  2952.         ignore_drag_release = (op_type != NOP);
  2953.     }
  2954.  
  2955.     /*
  2956.      * Jump!
  2957.      */
  2958.     if (!is_click)
  2959.         jump_flags |= MOUSE_DID_MOVE;
  2960.     save_buffer = curbuf;
  2961.     moved = (jump_to_mouse(jump_flags) & CURSOR_MOVED);
  2962.  
  2963.     /* When jumping to another buffer, stop visual mode */
  2964.     if (curbuf != save_buffer && VIsual_active)
  2965.     {
  2966.         end_visual_mode();
  2967.         update_curbuf(NOT_VALID);        /* delete the inversion */
  2968.     }
  2969.     else if (start_visual.lnum)        /* right click in visual mode */
  2970.     {
  2971.         /*
  2972.          * If the click is before the start of visual, change the start.  If
  2973.          * the click is after the end of visual, change the end.  If the click
  2974.          * is inside the visual, change the closest side.
  2975.          */
  2976.         if (lt(curwin->w_cursor, start_visual))
  2977.             VIsual = end_visual;
  2978.         else if (lt(end_visual, curwin->w_cursor))
  2979.             VIsual = start_visual;
  2980.         else
  2981.         {
  2982.             /* In the same line, compare column number */
  2983.             if (end_visual.lnum == start_visual.lnum)
  2984.             {
  2985.                 if (curwin->w_cursor.col - start_visual.col >
  2986.                                 end_visual.col - curwin->w_cursor.col)
  2987.                     VIsual = start_visual;
  2988.                 else
  2989.                     VIsual = end_visual;
  2990.             }
  2991.  
  2992.             /* In different lines, compare line number */
  2993.             else
  2994.             {
  2995.                 diff = (curwin->w_cursor.lnum - start_visual.lnum) -
  2996.                             (end_visual.lnum - curwin->w_cursor.lnum);
  2997.  
  2998.                 if (diff > 0)            /* closest to end */
  2999.                     VIsual = start_visual;
  3000.                 else if (diff < 0)        /* closest to start */
  3001.                     VIsual = end_visual;
  3002.                 else                    /* in the middle line */
  3003.                 {
  3004.                     if (curwin->w_cursor.col <
  3005.                                     (start_visual.col + end_visual.col) / 2)
  3006.                         VIsual = end_visual;
  3007.                     else
  3008.                         VIsual = start_visual;
  3009.                 }
  3010.             }
  3011.         }
  3012.     }
  3013.     /*
  3014.      * If Visual mode started in insert mode, execute "CTRL-O"
  3015.      */
  3016.     else if ((State & INSERT) && VIsual_active)
  3017.         stuffcharReadbuff(Ctrl('O'));
  3018.     /*
  3019.      * If cursor has moved, need to update Cline_row
  3020.      */
  3021.     else if (moved)
  3022.         cursupdate();
  3023.  
  3024.     /*
  3025.      * When the cursor has moved in insert mode, and something was inserted,
  3026.      * and there are several windows, need to redraw.
  3027.      */
  3028.     if (moved && (State & INSERT) && modified && firstwin->w_next != NULL)
  3029.     {
  3030.         update_curbuf(NOT_VALID);
  3031.         modified = FALSE;
  3032.     }
  3033.  
  3034.     /*
  3035.      * Middle mouse click: Put text before cursor.
  3036.      */
  3037.     if (which_button == MOUSE_MIDDLE)
  3038.     {
  3039. #ifdef USE_GUI
  3040.         if (gui.in_use && yankbuffer == 0)
  3041.             yankbuffer = '*';
  3042. #endif
  3043.         if (yank_buffer_mline())
  3044.         {
  3045.             if (mouse_past_bottom)
  3046.                 dir = FORWARD;
  3047.         }
  3048.         else if (mouse_past_eol)
  3049.             dir = FORWARD;
  3050.  
  3051.         if (fix_indent)
  3052.         {
  3053.             c1 = (dir == BACKWARD) ? '[' : ']';
  3054.             c2 = 'p';
  3055.         }
  3056.         else
  3057.         {
  3058.             c1 = (dir == FORWARD) ? 'p' : 'P';
  3059.             c2 = NUL;
  3060.         }
  3061.         prep_redo(Prenum, NUL, c1, c2, NUL);
  3062.         /*
  3063.          * Remember where the paste started, so in edit() Insstart can be set
  3064.          * to this position
  3065.          */
  3066.         if (restart_edit)
  3067.             where_paste_started = curwin->w_cursor;
  3068.         do_put(dir, count, fix_indent);
  3069.  
  3070.         /* Put cursor at the end of the just pasted text. */
  3071.         curwin->w_cursor = curbuf->b_op_end;
  3072.         if (restart_edit && gchar_cursor() != NUL)
  3073.             ++curwin->w_cursor.col;            /* put cursor after the text */
  3074.     }
  3075.  
  3076.     /*
  3077.      * Ctrl-Mouse click jumps to the tag under the mouse pointer
  3078.      */
  3079.     else if ((mod_mask & MOD_MASK_CTRL))
  3080.     {
  3081.         if (State & INSERT)
  3082.             stuffcharReadbuff(Ctrl('O'));
  3083.         stuffcharReadbuff(Ctrl(']'));
  3084.         ignore_drag_release = TRUE;        /* ignore drag and release now */
  3085.     }
  3086.  
  3087.     /*
  3088.      * Shift-Mouse click searches for the next occurrence of the word under
  3089.      * the mouse pointer
  3090.      */
  3091.     else if ((mod_mask & MOD_MASK_SHIFT))
  3092.     {
  3093.         if (State & INSERT)
  3094.             stuffcharReadbuff(Ctrl('O'));
  3095.         if (which_button == MOUSE_LEFT)
  3096.             stuffcharReadbuff('*');
  3097.         else    /* MOUSE_RIGHT */
  3098.             stuffcharReadbuff('#');
  3099.     }
  3100.  
  3101.     /* Handle double clicks */
  3102.     else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT)))
  3103.     {
  3104.         if (is_click || !VIsual_active)
  3105.         {
  3106.             if (VIsual_active)
  3107.                 orig_cursor = VIsual;
  3108.             else
  3109.             {
  3110.                 start_visual_highlight();
  3111.                 VIsual = curwin->w_cursor;
  3112.                 orig_cursor = VIsual;
  3113.                 VIsual_active = TRUE;
  3114. #ifdef USE_MOUSE
  3115.                 setmouse();
  3116. #endif
  3117.                 if (p_smd)
  3118.                     redraw_cmdline = TRUE;    /* show visual mode later */
  3119.             }
  3120.             if (mod_mask & MOD_MASK_2CLICK)
  3121.                 VIsual_mode = 'v';
  3122.             else if (mod_mask & MOD_MASK_3CLICK)
  3123.                 VIsual_mode = 'V';
  3124.             else if (mod_mask & MOD_MASK_4CLICK)
  3125.                 VIsual_mode = Ctrl('V');
  3126.         }
  3127.         if (mod_mask & MOD_MASK_2CLICK)
  3128.         {
  3129.             if (lt(curwin->w_cursor, orig_cursor))
  3130.             {
  3131.                 find_start_of_word(&curwin->w_cursor);
  3132.                 find_end_of_word(&VIsual);
  3133.             }
  3134.             else
  3135.             {
  3136.                 find_start_of_word(&VIsual);
  3137.                 find_end_of_word(&curwin->w_cursor);
  3138.             }
  3139.             curwin->w_set_curswant = TRUE;
  3140.         }
  3141.         if (is_click)
  3142.         {
  3143.             curs_columns(TRUE);                /* recompute w_virtcol */
  3144.             update_curbuf(NOT_VALID);        /* update the inversion */
  3145.         }
  3146.     }
  3147.     else if (VIsual_active && VIsual_was_active != VIsual_active)
  3148.         VIsual_mode = 'v';
  3149.  
  3150.     return moved;
  3151. }
  3152.  
  3153.     static void
  3154. find_start_of_word(pos)
  3155.     FPOS    *pos;
  3156. {
  3157.     char_u    *ptr;
  3158.     int        cclass;
  3159.  
  3160.     ptr = ml_get(pos->lnum);
  3161.     cclass = get_mouse_class(ptr[pos->col]);
  3162.  
  3163.     /* Can't test pos->col >= 0 because pos->col is unsigned */
  3164.     while (pos->col > 0 && get_mouse_class(ptr[pos->col]) == cclass)
  3165.         pos->col--;
  3166.     if (pos->col != 0 || get_mouse_class(ptr[0]) != cclass)
  3167.         pos->col++;
  3168. }
  3169.  
  3170.     static void
  3171. find_end_of_word(pos)
  3172.     FPOS    *pos;
  3173. {
  3174.     char_u    *ptr;
  3175.     int        cclass;
  3176.  
  3177.     ptr = ml_get(pos->lnum);
  3178.     cclass = get_mouse_class(ptr[pos->col]);
  3179.     while (ptr[pos->col] && get_mouse_class(ptr[pos->col]) == cclass)
  3180.         pos->col++;
  3181.     pos->col--;
  3182. }
  3183.  
  3184.     static int
  3185. get_mouse_class(c)
  3186.     int        c;
  3187. {
  3188.     if (c == ' ' || c == '\t')
  3189.         return ' ';
  3190.  
  3191.     if (isidchar(c))
  3192.         return 'a';
  3193.  
  3194.     /*
  3195.      * There are a few special cases where we want certain combinations of
  3196.      * characters to be considered as a single word.  These are things like
  3197.      * "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc.  Otherwise, each
  3198.      * character is in it's own class.
  3199.      */
  3200.     if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
  3201.         return '=';
  3202.     return c;
  3203. }
  3204. #endif /* USE_MOUSE */
  3205.  
  3206. /*
  3207.  * start highlighting for visual mode
  3208.  */
  3209.     void
  3210. start_visual_highlight()
  3211. {
  3212.     static int        didwarn = FALSE;        /* warned for broken inversion */
  3213.  
  3214.     if (!didwarn && set_highlight('v') == FAIL)/* cannot highlight */
  3215.     {
  3216.         EMSG("Warning: terminal cannot highlight");
  3217.         didwarn = TRUE;
  3218.     }
  3219. }
  3220.  
  3221. /*
  3222.  * End visual mode.  If we are using the GUI, and autoselect is set, then
  3223.  * remember what was selected in case we need to paste it somewhere while we
  3224.  * still own the selection.  This function should ALWAYS be called to end
  3225.  * visual mode.
  3226.  */
  3227.     void
  3228. end_visual_mode()
  3229. {
  3230. #ifdef USE_GUI
  3231.     if (gui.in_use)
  3232.         gui_auto_select();
  3233. #endif
  3234.     VIsual_active = FALSE;
  3235. #ifdef USE_MOUSE
  3236.     setmouse();
  3237. #endif
  3238.     VIsual_end = curwin->w_cursor;        /* remember for '> mark */
  3239.     if (p_smd)
  3240.         clear_cmdline = TRUE;            /* unshow visual mode later */
  3241. }
  3242.  
  3243. /*
  3244.  * Find the identifier under or to the right of the cursor.  If none is
  3245.  * found and find_type has FIND_STRING, then find any non-white string.  The
  3246.  * length of the string is returned, or zero if no string is found.  If a
  3247.  * string is found, a pointer to the string is put in *string, but note that
  3248.  * the caller must use the length returned as this string may not be NUL
  3249.  * terminated.
  3250.  */
  3251.     int
  3252. find_ident_under_cursor(string, find_type)
  3253.     char_u    **string;
  3254.     int        find_type;
  3255. {
  3256.     char_u    *ptr;
  3257.     int        col = 0;        /* init to shut up GCC */
  3258.     int        i;
  3259.  
  3260.     /*
  3261.      * if i == 0: try to find an identifier
  3262.      * if i == 1: try to find any string
  3263.      */
  3264.     ptr = ml_get_curline();
  3265.     for (i = (find_type & FIND_IDENT) ? 0 : 1;    i < 2; ++i)
  3266.     {
  3267.         /*
  3268.          * skip to start of identifier/string
  3269.          */
  3270.         col = curwin->w_cursor.col;
  3271.         while (ptr[col] != NUL &&
  3272.                     (i == 0 ? !iswordchar(ptr[col]) : vim_iswhite(ptr[col])))
  3273.             ++col;
  3274.  
  3275.         /*
  3276.          * Back up to start of identifier/string. This doesn't match the
  3277.          * real vi but I like it a little better and it shouldn't bother
  3278.          * anyone.
  3279.          * When FIND_IDENT isn't defined, we backup until a blank.
  3280.          */
  3281.         while (col > 0 && (i == 0 ? iswordchar(ptr[col - 1]) :
  3282.                     (!vim_iswhite(ptr[col - 1]) &&
  3283.                    (!(find_type & FIND_IDENT) || !iswordchar(ptr[col - 1])))))
  3284.             --col;
  3285.  
  3286.         /*
  3287.          * if we don't want just any old string, or we've found an identifier,
  3288.          * stop searching.
  3289.          */
  3290.         if (!(find_type & FIND_STRING) || iswordchar(ptr[col]))
  3291.             break;
  3292.     }
  3293.     /*
  3294.      * didn't find an identifier or string
  3295.      */
  3296.     if (ptr[col] == NUL || (!iswordchar(ptr[col]) && i == 0))
  3297.     {
  3298.         if (find_type & FIND_STRING)
  3299.             EMSG("No string under cursor");
  3300.         else
  3301.             EMSG("No identifier under cursor");
  3302.         return 0;
  3303.     }
  3304.     ptr += col;
  3305.     *string = ptr;
  3306.     col = 0;
  3307.     while (i == 0 ? iswordchar(*ptr) : (*ptr != NUL && !vim_iswhite(*ptr)))
  3308.     {
  3309.         ++ptr;
  3310.         ++col;
  3311.     }
  3312.     return col;
  3313. }
  3314.  
  3315.     static void
  3316. prep_redo(num, pre_char, cmd, c, nchar)
  3317.     long     num;
  3318.     int        pre_char;
  3319.     int        cmd;
  3320.     int        c;
  3321.     int        nchar;
  3322. {
  3323.     ResetRedobuff();
  3324.     if (yankbuffer != 0)    /* yank from specified buffer */
  3325.     {
  3326.         AppendCharToRedobuff('\"');
  3327.         AppendCharToRedobuff(yankbuffer);
  3328.     }
  3329.     if (num)
  3330.         AppendNumberToRedobuff(num);
  3331.     if (pre_char != NUL)
  3332.         AppendCharToRedobuff(pre_char);
  3333.     AppendCharToRedobuff(cmd);
  3334.     if (c != NUL)
  3335.         AppendCharToRedobuff(c);
  3336.     if (nchar != NUL)
  3337.         AppendCharToRedobuff(nchar);
  3338. }
  3339.  
  3340. /*
  3341.  * check for operator active and clear it
  3342.  *
  3343.  * return TRUE if operator was active
  3344.  */
  3345.     static int
  3346. checkclearop()
  3347. {
  3348.     if (op_type == NOP)
  3349.         return (FALSE);
  3350.     clearopbeep();
  3351.     return (TRUE);
  3352. }
  3353.  
  3354. /*
  3355.  * check for operator or Visual active and clear it
  3356.  *
  3357.  * return TRUE if operator was active
  3358.  */
  3359.     static int
  3360. checkclearopq()
  3361. {
  3362.     if (op_type == NOP && !VIsual_active)
  3363.         return (FALSE);
  3364.     clearopbeep();
  3365.     return (TRUE);
  3366. }
  3367.  
  3368.     static void
  3369. clearop()
  3370. {
  3371.     op_type = NOP;
  3372.     yankbuffer = 0;
  3373.     prechar = NUL;
  3374. }
  3375.  
  3376.     static void
  3377. clearopbeep()
  3378. {
  3379.     clearop();
  3380.     beep_flush();
  3381. }
  3382.  
  3383. /*
  3384.  * Routines for displaying a partly typed command
  3385.  */
  3386.  
  3387. static char_u    showcmd_buf[SHOWCMD_COLS + 1];
  3388. static char_u    old_showcmd_buf[SHOWCMD_COLS + 1];    /* For push_showcmd() */
  3389. static int        is_showcmd_clear = TRUE;
  3390.  
  3391. static void display_showcmd __ARGS((void));
  3392.  
  3393.     void
  3394. clear_showcmd()
  3395. {
  3396.     if (!p_sc)
  3397.         return;
  3398.  
  3399.     showcmd_buf[0] = NUL;
  3400.  
  3401.     /*
  3402.      * Don't actually display something if there is nothing to clear.
  3403.      */
  3404.     if (is_showcmd_clear)
  3405.         return;
  3406.  
  3407.     display_showcmd();
  3408. }
  3409.  
  3410. /*
  3411.  * Add 'c' to string of shown command chars.
  3412.  * Return TRUE if setcursor() has been called.
  3413.  */
  3414.     int
  3415. add_to_showcmd(c, display_always)
  3416.     int     c;
  3417.     int        display_always;
  3418. {
  3419.     char_u    *p;
  3420.     int        old_len;
  3421.     int        extra_len;
  3422.     int        overflow;
  3423.  
  3424.     if (!p_sc)
  3425.         return FALSE;
  3426.  
  3427.     p = transchar(c);
  3428.     old_len = STRLEN(showcmd_buf);
  3429.     extra_len = STRLEN(p);
  3430.     overflow = old_len + extra_len - SHOWCMD_COLS;
  3431.     if (overflow > 0)
  3432.         STRCPY(showcmd_buf, showcmd_buf + overflow);
  3433.     STRCAT(showcmd_buf, p);
  3434.  
  3435.     if (!display_always && char_avail())
  3436.         return FALSE;
  3437.  
  3438.     display_showcmd();
  3439.  
  3440.     return TRUE;
  3441. }
  3442.  
  3443. /*
  3444.  * Delete 'len' characters from the end of the shown command.
  3445.  */
  3446.     static void
  3447. del_from_showcmd(len)
  3448.     int     len;
  3449. {
  3450.     int        old_len;
  3451.  
  3452.     if (!p_sc)
  3453.         return;
  3454.  
  3455.     old_len = STRLEN(showcmd_buf);
  3456.     if (len > old_len)
  3457.         len = old_len;
  3458.     showcmd_buf[old_len - len] = NUL;
  3459.  
  3460.     if (!char_avail())
  3461.         display_showcmd();
  3462. }
  3463.  
  3464.     void
  3465. push_showcmd()
  3466. {
  3467.     if (p_sc)
  3468.         STRCPY(old_showcmd_buf, showcmd_buf);
  3469. }
  3470.  
  3471.     void
  3472. pop_showcmd()
  3473. {
  3474.     if (!p_sc)
  3475.         return;
  3476.  
  3477.     STRCPY(showcmd_buf, old_showcmd_buf);
  3478.  
  3479.     display_showcmd();
  3480. }
  3481.  
  3482.     static void
  3483. display_showcmd()
  3484. {
  3485.     int        len;
  3486.  
  3487.     cursor_off();
  3488.  
  3489.     len = STRLEN(showcmd_buf);
  3490.     if (len == 0)
  3491.         is_showcmd_clear = TRUE;
  3492.     else
  3493.     {
  3494.         screen_msg(showcmd_buf, (int)Rows - 1, sc_col);
  3495.         is_showcmd_clear = FALSE;
  3496.     }
  3497.  
  3498.     /*
  3499.      * clear the rest of an old message by outputing up to SHOWCMD_COLS spaces
  3500.      */
  3501.     screen_msg((char_u *)"          " + len, (int)Rows - 1, sc_col + len);
  3502.  
  3503.     setcursor();            /* put cursor back where it belongs */
  3504. }
  3505.  
  3506. /*
  3507.  * Implementation of "gd" and "gD" command.
  3508.  */
  3509.     static void
  3510. do_gd(nchar)
  3511.     int        nchar;
  3512. {
  3513.     int            len;
  3514.     char_u        *pat;
  3515.     FPOS        old_pos;
  3516.     int            t;
  3517.     int            save_p_ws;
  3518.     int            save_p_scs;
  3519.     char_u        *ptr;
  3520.  
  3521.     if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0 ||
  3522.                                                (pat = alloc(len + 5)) == NULL)
  3523.     {
  3524.         clearopbeep();
  3525.         return;
  3526.     }
  3527.     sprintf((char *)pat, iswordchar(*ptr) ? "\\<%.*s\\>" :
  3528.             "%.*s", len, ptr);
  3529.     old_pos = curwin->w_cursor;
  3530.     save_p_ws = p_ws;
  3531.     save_p_scs = p_scs;
  3532.     p_ws = FALSE;        /* don't wrap around end of file now */
  3533.     p_scs = FALSE;        /* don't switch ignorecase off now */
  3534.     fo_do_comments = TRUE;
  3535.  
  3536.     /*
  3537.      * Search back for the end of the previous function.
  3538.      * If this fails, and with "gD", go to line 1.
  3539.      * Search forward for the identifier, ignore comment lines.
  3540.      */
  3541.     if (nchar == 'D' || !findpar(BACKWARD, 1L, '}', FALSE))
  3542.     {
  3543.         setpcmark();                    /* Set in findpar() otherwise */
  3544.         curwin->w_cursor.lnum = 1;
  3545.     }
  3546.  
  3547.     while ((t = searchit(&curwin->w_cursor, FORWARD, pat, 1L, 0, RE_LAST))
  3548.                 == OK &&
  3549.             get_leader_len(ml_get_curline(), NULL) &&
  3550.             old_pos.lnum > curwin->w_cursor.lnum)
  3551.         ++curwin->w_cursor.lnum;
  3552.     if (t == FAIL || old_pos.lnum <= curwin->w_cursor.lnum)
  3553.     {
  3554.         clearopbeep();
  3555.         curwin->w_cursor = old_pos;
  3556.     }
  3557.     else
  3558.         curwin->w_set_curswant = TRUE;
  3559.  
  3560.     vim_free(pat);
  3561.     p_ws = save_p_ws;
  3562.     p_scs = save_p_scs;
  3563.     fo_do_comments = FALSE;
  3564. }
  3565.