[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.2

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