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

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