[BACK]Return to normal.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/normal.c, Revision 1.4

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