[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     ! 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: }