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

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