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

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