[BACK]Return to edit.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vim

Annotation of src/usr.bin/vim/edit.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:  * edit.c: functions for insert mode
        !            12:  */
        !            13:
        !            14: #include "vim.h"
        !            15: #include "globals.h"
        !            16: #include "proto.h"
        !            17: #include "option.h"
        !            18: #include "ops.h"   /* for op_type */
        !            19:
        !            20: #ifdef INSERT_EXPAND
        !            21: /*
        !            22:  * definitions used for CTRL-X submode
        !            23:  */
        !            24: #define CTRL_X_WANT_IDENT      0x100
        !            25:
        !            26: #define CTRL_X_NOT_DEFINED_YET (1)
        !            27: #define CTRL_X_SCROLL          (2)
        !            28: #define CTRL_X_WHOLE_LINE      (3)
        !            29: #define CTRL_X_FILES           (4)
        !            30: #define CTRL_X_TAGS                (5 + CTRL_X_WANT_IDENT)
        !            31: #define CTRL_X_PATH_PATTERNS   (6 + CTRL_X_WANT_IDENT)
        !            32: #define CTRL_X_PATH_DEFINES        (7 + CTRL_X_WANT_IDENT)
        !            33: #define CTRL_X_FINISHED            (8)
        !            34: #define CTRL_X_DICTIONARY      (9 + CTRL_X_WANT_IDENT)
        !            35:
        !            36: struct Completion
        !            37: {
        !            38:    char_u              *str;
        !            39:    char_u              *fname;
        !            40:    int                 original;
        !            41:    struct Completion   *next;
        !            42:    struct Completion   *prev;
        !            43: };
        !            44:
        !            45: struct Completion *first_match = NULL;
        !            46: struct Completion *curr_match = NULL;
        !            47:
        !            48: static int add_completion __ARGS((char_u *str, int len, char_u *, int dir));
        !            49: static int make_cyclic __ARGS((void));
        !            50: static void complete_dictionaries __ARGS((char_u *, int));
        !            51: static void free_completions __ARGS((void));
        !            52: static int count_completions __ARGS((void));
        !            53: #endif /* INSERT_EXPAND */
        !            54:
        !            55: #define BACKSPACE_CHAR             1
        !            56: #define BACKSPACE_WORD             2
        !            57: #define BACKSPACE_WORD_NOT_SPACE   3
        !            58: #define BACKSPACE_LINE             4
        !            59:
        !            60: static void change_indent __ARGS((int type, int amount, int round));
        !            61: static void insert_special __ARGS((int, int));
        !            62: static void start_arrow __ARGS((FPOS *end_insert_pos));
        !            63: static void stop_arrow __ARGS((void));
        !            64: static void stop_insert __ARGS((FPOS *end_insert_pos));
        !            65: static int echeck_abbr __ARGS((int));
        !            66:
        !            67: static FPOS    Insstart;       /* This is where the latest insert/append
        !            68:                                 * mode started. */
        !            69: static colnr_t Insstart_textlen;   /* length of line when insert started */
        !            70: static colnr_t Insstart_blank_vcol;    /* vcol for first inserted blank */
        !            71:
        !            72: static char_u  *last_insert = NULL;
        !            73:                            /* the text of the previous insert */
        !            74: static int     last_insert_skip;
        !            75:                            /* number of chars in front of previous insert */
        !            76: static int     new_insert_skip;
        !            77:                            /* number of chars in front of the current insert */
        !            78: #ifdef INSERT_EXPAND
        !            79: static char_u  *original_text = NULL;
        !            80:                            /* Original text typed before completion */
        !            81: #endif
        !            82:
        !            83: #ifdef CINDENT
        !            84: static int     can_cindent;    /* may do cindenting on this line */
        !            85: #endif
        !            86:
        !            87: /*
        !            88:  * edit() returns TRUE if it returns because of a CTRL-O command
        !            89:  */
        !            90:    int
        !            91: edit(initstr, startln, count)
        !            92:    int         initstr;
        !            93:    int         startln;        /* if set, insert at start of line */
        !            94:    long        count;
        !            95: {
        !            96:    int          c;
        !            97:    int          cc;
        !            98:    char_u      *ptr;
        !            99:    linenr_t     lnum;
        !           100:    int          temp = 0;
        !           101:    int          mode;
        !           102:    int          lastc = 0;
        !           103:    colnr_t      mincol;
        !           104:    static linenr_t o_lnum = 0;
        !           105:    static int   o_eol = FALSE;
        !           106:    int          need_redraw = FALSE;
        !           107:    int          i;
        !           108:    int          did_backspace = TRUE;      /* previous char was backspace */
        !           109: #ifdef RIGHTLEFT
        !           110:    int         revins;                     /* reverse insert mode */
        !           111:    int         revinschars = 0;            /* how much to skip after edit */
        !           112:    int         revinslegal = 0;            /* was the last char 'legal'? */
        !           113:    int         revinsscol = -1;            /* start column of revins session */
        !           114: #endif
        !           115: #ifdef INSERT_EXPAND
        !           116:    FPOS         first_match_pos;
        !           117:    FPOS         last_match_pos;
        !           118:    FPOS        *complete_pos;
        !           119:    char_u      *complete_pat = NULL;
        !           120:    char_u      *tmp_ptr;
        !           121:    char_u      *mesg = NULL;               /* Message about completion */
        !           122:    char_u      *quick_m;                   /* Message without sleep */
        !           123:    int          started_completion = FALSE;
        !           124:    colnr_t      complete_col = 0;          /* init for gcc */
        !           125:    int          complete_direction;
        !           126:    int          done_dir = 0;              /* Found all matches in this
        !           127:                                             * direction */
        !           128:    int          num_matches;
        !           129:    char_u      **matches;
        !           130:    regexp      *prog;
        !           131:    int          save_sm = -1;              /* init for gcc */
        !           132:    int          save_p_scs;
        !           133: #endif
        !           134: #ifdef CINDENT
        !           135:    int          line_is_white = FALSE;     /* line is empty before insert */
        !           136: #endif
        !           137:    FPOS         tpos;
        !           138:
        !           139:    /* sleep before redrawing, needed for "CTRL-O :" that results in an
        !           140:     * error message */
        !           141:    if (msg_scroll || emsg_on_display)
        !           142:    {
        !           143:        mch_delay(1000L, TRUE);
        !           144:        msg_scroll = FALSE;
        !           145:        emsg_on_display = FALSE;
        !           146:    }
        !           147: #ifdef SLEEP_IN_EMSG
        !           148:    if (need_sleep)
        !           149:    {
        !           150:        mch_delay(1000L, TRUE);
        !           151:        need_sleep = FALSE;
        !           152:    }
        !           153: #endif
        !           154:
        !           155: #ifdef USE_MOUSE
        !           156:    /*
        !           157:     * When doing a paste with the middle mouse button, Insstart is set to
        !           158:     * where the paste started.
        !           159:     */
        !           160:    if (where_paste_started.lnum != 0)
        !           161:        Insstart = where_paste_started;
        !           162:    else
        !           163: #endif
        !           164:    {
        !           165:        Insstart = curwin->w_cursor;
        !           166:        if (startln)
        !           167:            Insstart.col = 0;
        !           168:    }
        !           169:    Insstart_textlen = linetabsize(ml_get_curline());
        !           170:    Insstart_blank_vcol = MAXCOL;
        !           171:
        !           172:    if (initstr != NUL && !restart_edit)
        !           173:    {
        !           174:        ResetRedobuff();
        !           175:        AppendNumberToRedobuff(count);
        !           176:        AppendCharToRedobuff(initstr);
        !           177:        if (initstr == 'g')                 /* "gI" command */
        !           178:            AppendCharToRedobuff('I');
        !           179:    }
        !           180:
        !           181:    if (initstr == 'R')
        !           182:        State = REPLACE;
        !           183:    else
        !           184:        State = INSERT;
        !           185:
        !           186: #ifdef USE_MOUSE
        !           187:    setmouse();
        !           188: #endif
        !           189:    clear_showcmd();
        !           190: #ifdef RIGHTLEFT
        !           191:    revins = (State == INSERT && p_ri); /* there is no reverse replace mode */
        !           192:    if (revins)
        !           193:        undisplay_dollar();
        !           194: #endif
        !           195:
        !           196:    /*
        !           197:     * When CTRL-O . is used to repeat an insert, we get here with
        !           198:     * restart_edit non-zero, but something in the stuff buffer
        !           199:     */
        !           200:    if (restart_edit && stuff_empty())
        !           201:    {
        !           202: #ifdef USE_MOUSE
        !           203:        /*
        !           204:         * After a paste we consider text typed to be part of the insert for
        !           205:         * the pasted text. You can backspace over the paste text too.
        !           206:         */
        !           207:        if (where_paste_started.lnum)
        !           208:            arrow_used = FALSE;
        !           209:        else
        !           210: #endif
        !           211:            arrow_used = TRUE;
        !           212:        restart_edit = 0;
        !           213:        /*
        !           214:         * If the cursor was after the end-of-line before the CTRL-O
        !           215:         * and it is now at the end-of-line, put it after the end-of-line
        !           216:         * (this is not correct in very rare cases).
        !           217:         * Also do this if curswant is greater than the current virtual column.
        !           218:         * Eg after "^O$" or "^O80|".
        !           219:         */
        !           220:        if (((o_eol && curwin->w_cursor.lnum == o_lnum) ||
        !           221:                                curwin->w_curswant > curwin->w_virtcol) &&
        !           222:                *(ptr = ml_get_curline() + curwin->w_cursor.col)
        !           223:                                                                    != NUL &&
        !           224:                *(ptr + 1) == NUL)
        !           225:            ++curwin->w_cursor.col;
        !           226:    }
        !           227:    else
        !           228:    {
        !           229:        arrow_used = FALSE;
        !           230:        o_eol = FALSE;
        !           231:    }
        !           232: #ifdef USE_MOUSE
        !           233:    where_paste_started.lnum = 0;
        !           234: #endif
        !           235: #ifdef CINDENT
        !           236:    can_cindent = TRUE;
        !           237: #endif
        !           238:
        !           239:    if (p_smd)
        !           240:        showmode();
        !           241:
        !           242:    if (!p_im)
        !           243:        change_warning();           /* give a warning if readonly */
        !           244:
        !           245: #ifdef DIGRAPHS
        !           246:    do_digraph(-1);                 /* clear digraphs */
        !           247: #endif
        !           248:
        !           249: /*
        !           250:  * Get the current length of the redo buffer, those characters have to be
        !           251:  * skipped if we want to get to the inserted characters.
        !           252:  */
        !           253:    ptr = get_inserted();
        !           254:    new_insert_skip = STRLEN(ptr);
        !           255:    vim_free(ptr);
        !           256:
        !           257:    old_indent = 0;
        !           258:
        !           259:    for (;;)
        !           260:    {
        !           261: #ifdef RIGHTLEFT
        !           262:        if (!revinslegal)
        !           263:            revinsscol = -1;        /* reset on illegal motions */
        !           264:        else
        !           265:            revinslegal = 0;
        !           266: #endif
        !           267:        if (arrow_used)     /* don't repeat insert when arrow key used */
        !           268:            count = 0;
        !           269:
        !           270:            /* set curwin->w_curswant for next K_DOWN or K_UP */
        !           271:        if (!arrow_used)
        !           272:            curwin->w_set_curswant = TRUE;
        !           273:
        !           274:            /* Figure out where the cursor is based on curwin->w_cursor. */
        !           275:        mincol = curwin->w_col;
        !           276:        i = curwin->w_row;
        !           277:        cursupdate();
        !           278:
        !           279:        /*
        !           280:         * When emsg() was called msg_scroll will have been set.
        !           281:         */
        !           282:        msg_scroll = FALSE;
        !           283:
        !           284:        /*
        !           285:         * If we inserted a character at the last position of the last line in
        !           286:         * the window, scroll the window one line up. This avoids an extra
        !           287:         * redraw.
        !           288:         * This is detected when the cursor column is smaller after inserting
        !           289:         * something.
        !           290:         */
        !           291:        if (curwin->w_p_wrap && !did_backspace &&
        !           292:                          (int)curwin->w_col < (int)mincol - curbuf->b_p_ts &&
        !           293:                               i == curwin->w_winpos + curwin->w_height - 1 &&
        !           294:                                   curwin->w_cursor.lnum != curwin->w_topline)
        !           295:        {
        !           296:            ++curwin->w_topline;
        !           297:            updateScreen(VALID_TO_CURSCHAR);
        !           298:            cursupdate();
        !           299:            need_redraw = FALSE;
        !           300:        }
        !           301:        did_backspace = FALSE;
        !           302:
        !           303:        /*
        !           304:         * redraw is postponed until after cursupdate() to make 'dollar'
        !           305:         * option work correctly.
        !           306:         */
        !           307:        if (need_redraw)
        !           308:        {
        !           309:            updateline();
        !           310:            need_redraw = FALSE;
        !           311:        }
        !           312:
        !           313:        showruler(0);
        !           314:        setcursor();
        !           315:        emsg_on_display = FALSE;        /* may remove error message now */
        !           316:
        !           317:        c = vgetc();
        !           318:        if (c == Ctrl('C'))
        !           319:            got_int = FALSE;
        !           320:
        !           321: #ifdef RIGHTLEFT
        !           322:        if (p_hkmap && KeyTyped)
        !           323:            c = hkmap(c);               /* Hebrew mode mapping */
        !           324: #endif
        !           325:
        !           326: #ifdef INSERT_EXPAND
        !           327:        if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
        !           328:        {
        !           329:            /* We have just entered ctrl-x mode and aren't quite sure which
        !           330:             * ctrl-x mode it will be yet.  Now we decide -- webb
        !           331:             */
        !           332:            switch (c)
        !           333:            {
        !           334:                case Ctrl('E'):
        !           335:                case Ctrl('Y'):
        !           336:                    ctrl_x_mode = CTRL_X_SCROLL;
        !           337:                    if (State == INSERT)
        !           338:                        edit_submode = (char_u *)" (insert) Scroll (^E/^Y)";
        !           339:                    else
        !           340:                        edit_submode = (char_u *)" (replace) Scroll (^E/^Y)";
        !           341:                    break;
        !           342:                case Ctrl('L'):
        !           343:                    ctrl_x_mode = CTRL_X_WHOLE_LINE;
        !           344:                    edit_submode = (char_u *)" Whole line completion (^L/^N/^P)";
        !           345:                    break;
        !           346:                case Ctrl('F'):
        !           347:                    ctrl_x_mode = CTRL_X_FILES;
        !           348:                    edit_submode = (char_u *)" File name completion (^F/^N/^P)";
        !           349:                    break;
        !           350:                case Ctrl('K'):
        !           351:                    ctrl_x_mode = CTRL_X_DICTIONARY;
        !           352:                    edit_submode = (char_u *)" Dictionary completion (^K/^N/^P)";
        !           353:                    break;
        !           354:                case Ctrl(']'):
        !           355:                    ctrl_x_mode = CTRL_X_TAGS;
        !           356:                    edit_submode = (char_u *)" Tag completion (^]/^N/^P)";
        !           357:                    break;
        !           358:                case Ctrl('I'):
        !           359:                    ctrl_x_mode = CTRL_X_PATH_PATTERNS;
        !           360:                    edit_submode = (char_u *)" Path pattern completion (^N/^P)";
        !           361:                    break;
        !           362:                case Ctrl('D'):
        !           363:                    ctrl_x_mode = CTRL_X_PATH_DEFINES;
        !           364:                    edit_submode = (char_u *)" Definition completion (^D/^N/^P)";
        !           365:                    break;
        !           366:                default:
        !           367:                    ctrl_x_mode = 0;
        !           368:                    break;
        !           369:            }
        !           370:            showmode();
        !           371:        }
        !           372:        else if (ctrl_x_mode)
        !           373:        {
        !           374:            /* We we're already in ctrl-x mode, do we stay in it? */
        !           375:            if (!is_ctrl_x_key(c))
        !           376:            {
        !           377:                if (ctrl_x_mode == CTRL_X_SCROLL)
        !           378:                    ctrl_x_mode = 0;
        !           379:                else
        !           380:                    ctrl_x_mode = CTRL_X_FINISHED;
        !           381:                edit_submode = NULL;
        !           382:            }
        !           383:            showmode();
        !           384:        }
        !           385:        if (started_completion || ctrl_x_mode == CTRL_X_FINISHED)
        !           386:        {
        !           387:            /* Show error message from attempted keyword completion (probably
        !           388:             * 'Pattern not found') until another key is hit, then go back to
        !           389:             * showing what mode we are in.
        !           390:             */
        !           391:            showmode();
        !           392:            if ((ctrl_x_mode == 0 && c != Ctrl('N') && c != Ctrl('P')) ||
        !           393:                                                ctrl_x_mode == CTRL_X_FINISHED)
        !           394:            {
        !           395:                /* Get here when we have finished typing a sequence of ^N and
        !           396:                 * ^P or other completion characters in CTRL-X mode. Free up
        !           397:                 * memory that was used, and make sure we can redo the insert
        !           398:                 * -- webb.
        !           399:                 */
        !           400:                if (curr_match != NULL)
        !           401:                {
        !           402:                    /*
        !           403:                     * If any of the original typed text has been changed,
        !           404:                     * eg when ignorecase is set, we must add back-spaces to
        !           405:                     * the redo buffer.  We add as few as necessary to delete
        !           406:                     * just the part of the original text that has changed
        !           407:                     * -- webb
        !           408:                     */
        !           409:                    ptr = curr_match->str;
        !           410:                    tmp_ptr = original_text;
        !           411:                    while (*tmp_ptr && *tmp_ptr == *ptr)
        !           412:                    {
        !           413:                        ++tmp_ptr;
        !           414:                        ++ptr;
        !           415:                    }
        !           416:                    for (temp = 0; tmp_ptr[temp]; ++temp)
        !           417:                        AppendCharToRedobuff(K_BS);
        !           418:                    if (*ptr)
        !           419:                        AppendToRedobuff(ptr);
        !           420:                }
        !           421:                /* Break line if it's too long */
        !           422:                lnum = curwin->w_cursor.lnum;
        !           423:                insertchar(NUL, FALSE, -1);
        !           424:                if (lnum != curwin->w_cursor.lnum)
        !           425:                    updateScreen(CURSUPD);
        !           426:                else
        !           427:                    need_redraw = TRUE;
        !           428:
        !           429:                vim_free(complete_pat);
        !           430:                complete_pat = NULL;
        !           431:                vim_free(original_text);
        !           432:                original_text = NULL;
        !           433:                free_completions();
        !           434:                started_completion = FALSE;
        !           435:                ctrl_x_mode = 0;
        !           436:                p_sm = save_sm;
        !           437:                if (edit_submode != NULL)
        !           438:                {
        !           439:                    edit_submode = NULL;
        !           440:                    showmode();
        !           441:                }
        !           442:            }
        !           443:        }
        !           444: #endif /* INSERT_EXPAND */
        !           445:
        !           446:        if (c != Ctrl('D'))         /* remember to detect ^^D and 0^D */
        !           447:            lastc = c;
        !           448:
        !           449: #ifdef DIGRAPHS
        !           450:        c = do_digraph(c);
        !           451: #endif /* DIGRAPHS */
        !           452:
        !           453:        if (c == Ctrl('V') || c == Ctrl('Q'))
        !           454:        {
        !           455:            if (NextScreen != NULL)
        !           456:                screen_outchar('^', curwin->w_winpos + curwin->w_row,
        !           457: #ifdef RIGHTLEFT
        !           458:                    curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
        !           459: #endif
        !           460:                                                               curwin->w_col);
        !           461:            AppendToRedobuff((char_u *)"\026"); /* CTRL-V */
        !           462:            cursupdate();
        !           463:
        !           464:            if (!add_to_showcmd(c, FALSE))
        !           465:                setcursor();
        !           466:
        !           467:            c = get_literal();
        !           468:            clear_showcmd();
        !           469:            insert_special(c, TRUE);
        !           470:            need_redraw = TRUE;
        !           471: #ifdef RIGHTLEFT
        !           472:            revinschars++;
        !           473:            revinslegal++;
        !           474: #endif
        !           475:            continue;
        !           476:        }
        !           477:
        !           478: #ifdef CINDENT
        !           479:        if (curbuf->b_p_cin
        !           480: # ifdef INSERT_EXPAND
        !           481:                            && !ctrl_x_mode
        !           482: # endif
        !           483:                                               )
        !           484:        {
        !           485:            line_is_white = inindent(0);
        !           486:
        !           487:            /*
        !           488:             * A key name preceded by a bang means that this
        !           489:             * key wasn't destined to be inserted.  Skip ahead
        !           490:             * to the re-indenting if we find one.
        !           491:             */
        !           492:            if (in_cinkeys(c, '!', line_is_white))
        !           493:                goto force_cindent;
        !           494:
        !           495:            /*
        !           496:             * A key name preceded by a star means that indenting
        !           497:             * has to be done before inserting the key.
        !           498:             */
        !           499:            if (can_cindent && in_cinkeys(c, '*', line_is_white))
        !           500:            {
        !           501:                stop_arrow();
        !           502:
        !           503:                /* re-indent the current line */
        !           504:                fixthisline(get_c_indent);
        !           505:
        !           506:                /* draw the changes on the screen later */
        !           507:                need_redraw = TRUE;
        !           508:            }
        !           509:        }
        !           510: #endif /* CINDENT */
        !           511:
        !           512: #ifdef RIGHTLEFT
        !           513:        if (curwin->w_p_rl)
        !           514:            switch (c)
        !           515:            {
        !           516:                case K_LEFT:    c = K_RIGHT; break;
        !           517:                case K_S_LEFT:  c = K_S_RIGHT; break;
        !           518:                case K_RIGHT:   c = K_LEFT; break;
        !           519:                case K_S_RIGHT: c = K_S_LEFT; break;
        !           520:            }
        !           521: #endif
        !           522:
        !           523:        switch (c)      /* handle character in insert mode */
        !           524:        {
        !           525:              case K_INS:           /* toggle insert/replace mode */
        !           526:                if (State == REPLACE)
        !           527:                    State = INSERT;
        !           528:                else
        !           529:                    State = REPLACE;
        !           530:                AppendCharToRedobuff(K_INS);
        !           531:                showmode();
        !           532:                break;
        !           533:
        !           534: #ifdef INSERT_EXPAND
        !           535:              case Ctrl('X'):       /* Enter ctrl-x mode */
        !           536:                /* We're not sure which ctrl-x mode it will be yet */
        !           537:                ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
        !           538:                MSG("^X mode (^E/^Y/^L/^]/^F/^I/^K/^D)");
        !           539:                break;
        !           540: #endif /* INSERT_EXPAND */
        !           541:
        !           542:              case Ctrl('O'):       /* execute one command */
        !           543:                if (echeck_abbr(Ctrl('O') + ABBR_OFF))
        !           544:                    break;
        !           545:                count = 0;
        !           546:                if (State == INSERT)
        !           547:                    restart_edit = 'I';
        !           548:                else
        !           549:                    restart_edit = 'R';
        !           550:                o_lnum = curwin->w_cursor.lnum;
        !           551:                o_eol = (gchar_cursor() == NUL);
        !           552:                goto doESCkey;
        !           553:
        !           554:              /* Hitting the help key in insert mode is like <ESC> <Help> */
        !           555:              case K_HELP:
        !           556:              case K_F1:
        !           557:                stuffcharReadbuff(K_HELP);
        !           558:                /*FALLTHROUGH*/
        !           559:
        !           560:              case ESC:             /* an escape ends input mode */
        !           561:                if (echeck_abbr(ESC + ABBR_OFF))
        !           562:                    break;
        !           563:                /*FALLTHROUGH*/
        !           564:
        !           565:              case Ctrl('C'):
        !           566: doESCkey:
        !           567:                temp = curwin->w_cursor.col;
        !           568:                if (!arrow_used)
        !           569:                {
        !           570:                    AppendToRedobuff(ESC_STR);
        !           571:
        !           572:                    if (--count > 0)        /* repeat what was typed */
        !           573:                    {
        !           574:                        (void)start_redo_ins();
        !           575:                        continue;
        !           576:                    }
        !           577:                    stop_insert(&curwin->w_cursor);
        !           578:                    if (dollar_vcol)
        !           579:                    {
        !           580:                        dollar_vcol = 0;
        !           581:                        /* may have to redraw status line if this was the
        !           582:                         * first change, show "[+]" */
        !           583:                        if (curwin->w_redr_status == TRUE)
        !           584:                            must_redraw = NOT_VALID;
        !           585:                        else
        !           586:                            need_redraw = TRUE;
        !           587:                    }
        !           588:                }
        !           589:                if (need_redraw)
        !           590:                    updateline();
        !           591:
        !           592:                /* When an autoindent was removed, curswant stays after the
        !           593:                 * indent */
        !           594:                if (!restart_edit && (colnr_t)temp == curwin->w_cursor.col)
        !           595:                    curwin->w_set_curswant = TRUE;
        !           596:
        !           597:                /*
        !           598:                 * The cursor should end up on the last inserted character.
        !           599:                 */
        !           600:                if (curwin->w_cursor.col != 0 &&
        !           601:                          (!restart_edit || gchar_cursor() == NUL)
        !           602: #ifdef RIGHTLEFT
        !           603:                                      && !revins
        !           604: #endif
        !           605:                                                  )
        !           606:                    --curwin->w_cursor.col;
        !           607:                if (State == REPLACE)
        !           608:                    replace_flush();    /* free replace stack */
        !           609:                State = NORMAL;
        !           610: #ifdef USE_MOUSE
        !           611:                setmouse();
        !           612: #endif
        !           613:                    /* inchar() may have deleted the "INSERT" message */
        !           614:                    /* for CTRL-O we display -- INSERT COMMAND -- */
        !           615:                if (Recording || restart_edit)
        !           616:                    showmode();
        !           617:                else if (p_smd)
        !           618:                    MSG("");
        !           619:                old_indent = 0;
        !           620:                return (c == Ctrl('O'));
        !           621:
        !           622:                /*
        !           623:                 * Insert the previously inserted text.
        !           624:                 * For ^@ the trailing ESC will end the insert, unless there
        !           625:                 * is an error.
        !           626:                 */
        !           627:              case K_ZERO:
        !           628:              case NUL:
        !           629:              case Ctrl('A'):
        !           630:                if (stuff_inserted(NUL, 1L, (c == Ctrl('A'))) == FAIL &&
        !           631:                                                               c != Ctrl('A'))
        !           632:                    goto doESCkey;          /* quit insert mode */
        !           633:                break;
        !           634:
        !           635:                /*
        !           636:                 * insert the contents of a register
        !           637:                 */
        !           638:              case Ctrl('R'):
        !           639:                if (NextScreen != NULL)
        !           640:                    screen_outchar('"', curwin->w_winpos + curwin->w_row,
        !           641: #ifdef RIGHTLEFT
        !           642:                        curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
        !           643: #endif
        !           644:                                                            curwin->w_col);
        !           645:                if (!add_to_showcmd(c, FALSE))
        !           646:                    setcursor();
        !           647:                    /* don't map the register name. This also prevents the
        !           648:                     * mode message to be deleted when ESC is hit */
        !           649:                ++no_mapping;
        !           650: #ifdef HAVE_LANGMAP
        !           651:                cc = vgetc();
        !           652:                LANGMAP_ADJUST(cc, TRUE);
        !           653:                if (insertbuf(cc) == FAIL)
        !           654: #else
        !           655:                if (insertbuf(vgetc()) == FAIL)
        !           656: #endif
        !           657:                {
        !           658:                    beep_flush();
        !           659:                    need_redraw = TRUE;     /* remove the '"' */
        !           660:                }
        !           661:                --no_mapping;
        !           662:                clear_showcmd();
        !           663:                break;
        !           664:
        !           665: #ifdef RIGHTLEFT
        !           666:              case Ctrl('B'):           /* toggle reverse insert mode */
        !           667:                p_ri = !p_ri;
        !           668:                revins = (State == INSERT && p_ri);
        !           669:                if (revins)
        !           670:                    undisplay_dollar();
        !           671:                showmode();
        !           672:                break;
        !           673:
        !           674:              case Ctrl('_'):       /* toggle language: khmap and revins */
        !           675:                                    /* Move to end of reverse inserted text */
        !           676:                if (revins && revinschars && revinsscol >= 0)
        !           677:                    while (gchar_cursor() != NUL && revinschars--)
        !           678:                        ++curwin->w_cursor.col;
        !           679:                p_ri = !p_ri;
        !           680:                revins = (State == INSERT && p_ri);
        !           681:                if (revins)
        !           682:                {
        !           683:                    revinsscol = curwin->w_cursor.col;
        !           684:                    revinslegal++;
        !           685:                    revinschars = 0;
        !           686:                    undisplay_dollar();
        !           687:                }
        !           688:                else
        !           689:                    revinsscol = -1;
        !           690:                p_hkmap = curwin->w_p_rl ^ p_ri;    /* be consistent! */
        !           691:                showmode();
        !           692:                break;
        !           693: #endif
        !           694:
        !           695:                /*
        !           696:                 * If the cursor is on an indent, ^T/^D insert/delete one
        !           697:                 * shiftwidth.  Otherwise ^T/^D behave like a "<<" or ">>".
        !           698:                 * Always round the indent to 'shiftwith', this is compatible
        !           699:                 * with vi.  But vi only supports ^T and ^D after an
        !           700:                 * autoindent, we support it everywhere.
        !           701:                 */
        !           702:              case Ctrl('D'):       /* make indent one shiftwidth smaller */
        !           703: #ifdef INSERT_EXPAND
        !           704:                if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
        !           705:                    goto docomplete;
        !           706: #endif /* INSERT_EXPAND */
        !           707:                /* FALLTHROUGH */
        !           708:              case Ctrl('T'):       /* make indent one shiftwidth greater */
        !           709:                stop_arrow();
        !           710:                AppendCharToRedobuff(c);
        !           711:
        !           712:                /*
        !           713:                 * 0^D and ^^D: remove all indent.
        !           714:                 */
        !           715:                if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
        !           716:                {
        !           717:                    --curwin->w_cursor.col;
        !           718:                    (void)delchar(FALSE);           /* delete the '^' or '0' */
        !           719:                    if (lastc == '^')
        !           720:                        old_indent = get_indent();  /* remember curr. indent */
        !           721:                    change_indent(INDENT_SET, 0, TRUE);
        !           722:                }
        !           723:                else
        !           724:                    change_indent(c == Ctrl('D') ? INDENT_DEC : INDENT_INC,
        !           725:                                                                     0, TRUE);
        !           726:
        !           727:                did_ai = FALSE;
        !           728:                did_si = FALSE;
        !           729:                can_si = FALSE;
        !           730:                can_si_back = FALSE;
        !           731: #ifdef CINDENT
        !           732:                can_cindent = FALSE;        /* no cindenting after ^D or ^T */
        !           733: #endif
        !           734:                goto redraw;
        !           735:
        !           736:              case K_DEL:
        !           737:                stop_arrow();
        !           738:                if (gchar_cursor() == NUL)      /* delete newline */
        !           739:                {
        !           740:                    temp = curwin->w_cursor.col;
        !           741:                    if (!p_bs ||                /* only if 'bs' set */
        !           742:                        u_save((linenr_t)(curwin->w_cursor.lnum - 1),
        !           743:                            (linenr_t)(curwin->w_cursor.lnum + 2)) == FAIL ||
        !           744:                                do_join(FALSE, TRUE) == FAIL)
        !           745:                        beep_flush();
        !           746:                    else
        !           747:                        curwin->w_cursor.col = temp;
        !           748:                }
        !           749:                else if (delchar(FALSE) == FAIL)/* delete char under cursor */
        !           750:                    beep_flush();
        !           751:                did_ai = FALSE;
        !           752:                did_si = FALSE;
        !           753:                can_si = FALSE;
        !           754:                can_si_back = FALSE;
        !           755:                AppendCharToRedobuff(c);
        !           756:                goto redraw;
        !           757:
        !           758:              case K_BS:
        !           759:              case Ctrl('H'):
        !           760:                mode = BACKSPACE_CHAR;
        !           761: dodel:
        !           762:                /* can't delete anything in an empty file */
        !           763:                /* can't backup past first character in buffer */
        !           764:                /* can't backup past starting point unless 'backspace' > 1 */
        !           765:                /* can backup to a previous line if 'backspace' == 0 */
        !           766:                if (bufempty() || (
        !           767: #ifdef RIGHTLEFT
        !           768:                        !revins &&
        !           769: #endif
        !           770:                        ((curwin->w_cursor.lnum == 1 &&
        !           771:                                    curwin->w_cursor.col <= 0) ||
        !           772:                        (p_bs < 2 && (arrow_used ||
        !           773:                            (curwin->w_cursor.lnum == Insstart.lnum &&
        !           774:                            curwin->w_cursor.col <= Insstart.col) ||
        !           775:                            (curwin->w_cursor.col <= 0 && p_bs == 0))))))
        !           776:                {
        !           777:                    beep_flush();
        !           778:                    goto redraw;
        !           779:                }
        !           780:
        !           781:                stop_arrow();
        !           782: #ifdef CINDENT
        !           783:                if (inindent(0))
        !           784:                    can_cindent = FALSE;
        !           785: #endif
        !           786: #ifdef RIGHTLEFT
        !           787:                if (revins)         /* put cursor after last inserted char */
        !           788:                    inc_cursor();
        !           789: #endif
        !           790:                if (curwin->w_cursor.col <= 0)      /* delete newline! */
        !           791:                {
        !           792:                    lnum = Insstart.lnum;
        !           793:                    if (curwin->w_cursor.lnum == Insstart.lnum
        !           794: #ifdef RIGHTLEFT
        !           795:                                    || revins
        !           796: #endif
        !           797:                                                )
        !           798:                    {
        !           799:                        if (u_save((linenr_t)(curwin->w_cursor.lnum - 2),
        !           800:                                (linenr_t)(curwin->w_cursor.lnum + 1)) == FAIL)
        !           801:                            goto redraw;
        !           802:                        --Insstart.lnum;
        !           803:                        Insstart.col = 0;
        !           804:                    }
        !           805:                    /*
        !           806:                     * In replace mode:
        !           807:                     * cc < 0: NL was inserted, delete it
        !           808:                     * cc >= 0: NL was replaced, put original characters back
        !           809:                     */
        !           810:                    cc = -1;
        !           811:                    if (State == REPLACE)
        !           812:                        cc = replace_pop();
        !           813:                /* in replace mode, in the line we started replacing, we
        !           814:                                                        only move the cursor */
        !           815:                    if (State != REPLACE || curwin->w_cursor.lnum > lnum)
        !           816:                    {
        !           817:                        temp = gchar_cursor();      /* remember current char */
        !           818:                        --curwin->w_cursor.lnum;
        !           819:                        (void)do_join(FALSE, curs_rows() == OK);
        !           820:                        if (temp == NUL && gchar_cursor() != NUL)
        !           821:                            ++curwin->w_cursor.col;
        !           822:                        /*
        !           823:                         * in REPLACE mode we have to put back the text that
        !           824:                         * was replace by the NL. On the replace stack is
        !           825:                         * first a NUL-terminated sequence of characters that
        !           826:                         * were deleted and then the character that NL
        !           827:                         * replaced.
        !           828:                         */
        !           829:                        if (State == REPLACE)
        !           830:                        {
        !           831:                            /*
        !           832:                             * Do the next ins_char() in NORMAL state, to
        !           833:                             * prevent ins_char() from replacing characters and
        !           834:                             * avoiding showmatch().
        !           835:                             */
        !           836:                            State = NORMAL;
        !           837:                            /*
        !           838:                             * restore blanks deleted after cursor
        !           839:                             */
        !           840:                            while (cc > 0)
        !           841:                            {
        !           842:                                temp = curwin->w_cursor.col;
        !           843:                                ins_char(cc);
        !           844:                                curwin->w_cursor.col = temp;
        !           845:                                cc = replace_pop();
        !           846:                            }
        !           847:                            cc = replace_pop();
        !           848:                            if (cc > 0)
        !           849:                            {
        !           850:                                ins_char(cc);
        !           851:                                dec_cursor();
        !           852:                            }
        !           853:                            State = REPLACE;
        !           854:                        }
        !           855:                    }
        !           856:                    else
        !           857:                        dec_cursor();
        !           858:                    did_ai = FALSE;
        !           859:                }
        !           860:                else
        !           861:                {
        !           862: #ifdef RIGHTLEFT
        !           863:                    if (revins)         /* put cursor on last inserted char */
        !           864:                        dec_cursor();
        !           865: #endif
        !           866:                    mincol = 0;
        !           867:                                                            /* keep indent */
        !           868:                    if (mode == BACKSPACE_LINE && curbuf->b_p_ai
        !           869: #ifdef RIGHTLEFT
        !           870:                            && !revins
        !           871: #endif
        !           872:                                        )
        !           873:                    {
        !           874:                        temp = curwin->w_cursor.col;
        !           875:                        beginline(TRUE);
        !           876:                        if (curwin->w_cursor.col < (colnr_t)temp)
        !           877:                            mincol = curwin->w_cursor.col;
        !           878:                        curwin->w_cursor.col = temp;
        !           879:                    }
        !           880:
        !           881:                    /* delete upto starting point, start of line or previous
        !           882:                     * word */
        !           883:                    do
        !           884:                    {
        !           885: #ifdef RIGHTLEFT
        !           886:                        if (!revins)    /* put cursor on char to be deleted */
        !           887: #endif
        !           888:                            dec_cursor();
        !           889:
        !           890:                                /* start of word? */
        !           891:                        if (mode == BACKSPACE_WORD &&
        !           892:                                                !vim_isspace(gchar_cursor()))
        !           893:                        {
        !           894:                            mode = BACKSPACE_WORD_NOT_SPACE;
        !           895:                            temp = iswordchar(gchar_cursor());
        !           896:                        }
        !           897:                                /* end of word? */
        !           898:                        else if (mode == BACKSPACE_WORD_NOT_SPACE &&
        !           899:                                          (vim_isspace(cc = gchar_cursor()) ||
        !           900:                                                      iswordchar(cc) != temp))
        !           901:                        {
        !           902: #ifdef RIGHTLEFT
        !           903:                            if (!revins)
        !           904: #endif
        !           905:                                inc_cursor();
        !           906: #ifdef RIGHTLEFT
        !           907:                            else if (State == REPLACE)
        !           908:                                dec_cursor();
        !           909: #endif
        !           910:                            break;
        !           911:                        }
        !           912:                        if (State == REPLACE)
        !           913:                        {
        !           914:                            /*
        !           915:                             * cc < 0: replace stack empty, just move cursor
        !           916:                             * cc == 0: character was inserted, delete it
        !           917:                             * cc > 0: character was replace, put original back
        !           918:                             */
        !           919:                            cc = replace_pop();
        !           920:                            if (cc > 0)
        !           921:                                pchar_cursor(cc);
        !           922:                            else if (cc == 0)
        !           923:                                (void)delchar(FALSE);
        !           924:                        }
        !           925:                        else  /* State != REPLACE */
        !           926:                        {
        !           927:                            (void)delchar(FALSE);
        !           928: #ifdef RIGHTLEFT
        !           929:                            if (revinschars)
        !           930:                            {
        !           931:                                revinschars--;
        !           932:                                revinslegal++;
        !           933:                            }
        !           934:                            if (revins && gchar_cursor() == NUL)
        !           935:                                break;
        !           936: #endif
        !           937:                        }
        !           938:                        /* Just a single backspace?: */
        !           939:                        if (mode == BACKSPACE_CHAR)
        !           940:                            break;
        !           941:                    } while (
        !           942: #ifdef RIGHTLEFT
        !           943:                            revins ||
        !           944: #endif
        !           945:                            (curwin->w_cursor.col > mincol &&
        !           946:                            (curwin->w_cursor.lnum != Insstart.lnum ||
        !           947:                            curwin->w_cursor.col != Insstart.col)));
        !           948:                    did_backspace = TRUE;
        !           949:                }
        !           950:                did_si = FALSE;
        !           951:                can_si = FALSE;
        !           952:                can_si_back = FALSE;
        !           953:                if (curwin->w_cursor.col <= 1)
        !           954:                    did_ai = FALSE;
        !           955:                /*
        !           956:                 * It's a little strange to put backspaces into the redo
        !           957:                 * buffer, but it makes auto-indent a lot easier to deal
        !           958:                 * with.
        !           959:                 */
        !           960:                AppendCharToRedobuff(c);
        !           961: redraw:
        !           962:                need_redraw = TRUE;
        !           963:                break;
        !           964:
        !           965:              case Ctrl('W'):       /* delete word before cursor */
        !           966:                mode = BACKSPACE_WORD;
        !           967:                goto dodel;
        !           968:
        !           969:              case Ctrl('U'):       /* delete inserted text in current line */
        !           970:                mode = BACKSPACE_LINE;
        !           971:                goto dodel;
        !           972:
        !           973: #ifdef USE_MOUSE
        !           974:              case K_LEFTMOUSE:
        !           975:              case K_LEFTDRAG:
        !           976:              case K_LEFTRELEASE:
        !           977:              case K_MIDDLEMOUSE:
        !           978:              case K_MIDDLEDRAG:
        !           979:              case K_MIDDLERELEASE:
        !           980:              case K_RIGHTMOUSE:
        !           981:              case K_RIGHTDRAG:
        !           982:              case K_RIGHTRELEASE:
        !           983: #ifdef USE_GUI
        !           984:                /* When GUI is active, also move/paste when 'mouse' is empty */
        !           985:                if (!gui.in_use)
        !           986: #endif
        !           987:                    if (!mouse_has(MOUSE_INSERT))
        !           988:                        break;
        !           989:
        !           990:                undisplay_dollar();
        !           991:                tpos = curwin->w_cursor;
        !           992:                if (do_mouse(c, BACKWARD, 1L, FALSE))
        !           993:                {
        !           994:                    start_arrow(&tpos);
        !           995: # ifdef CINDENT
        !           996:                    can_cindent = TRUE;
        !           997: # endif
        !           998:                }
        !           999:
        !          1000:                break;
        !          1001:
        !          1002:              case K_IGNORE:
        !          1003:                break;
        !          1004: #endif
        !          1005:
        !          1006: #ifdef USE_GUI
        !          1007:              case K_SCROLLBAR:
        !          1008:                undisplay_dollar();
        !          1009:                tpos = curwin->w_cursor;
        !          1010:                if (gui_do_scroll())
        !          1011:                {
        !          1012:                    start_arrow(&tpos);
        !          1013: # ifdef CINDENT
        !          1014:                    can_cindent = TRUE;
        !          1015: # endif
        !          1016:                }
        !          1017:                break;
        !          1018:
        !          1019:              case K_HORIZ_SCROLLBAR:
        !          1020:                undisplay_dollar();
        !          1021:                tpos = curwin->w_cursor;
        !          1022:                if (gui_do_horiz_scroll())
        !          1023:                {
        !          1024:                    start_arrow(&tpos);
        !          1025: #ifdef CINDENT
        !          1026:                    can_cindent = TRUE;
        !          1027: #endif
        !          1028:                }
        !          1029:                break;
        !          1030: #endif
        !          1031:
        !          1032:              case K_LEFT:
        !          1033:                undisplay_dollar();
        !          1034:                tpos = curwin->w_cursor;
        !          1035:                if (oneleft() == OK)
        !          1036:                {
        !          1037:                    start_arrow(&tpos);
        !          1038: #ifdef RIGHTLEFT
        !          1039:                    /* If exit reversed string, position is fixed */
        !          1040:                    if (revinsscol != -1 &&
        !          1041:                                      (int)curwin->w_cursor.col >= revinsscol)
        !          1042:                        revinslegal++;
        !          1043:                    revinschars++;
        !          1044: #endif
        !          1045:                }
        !          1046:
        !          1047:                /*
        !          1048:                 * if 'whichwrap' set for cursor in insert mode may go to
        !          1049:                 * previous line
        !          1050:                 */
        !          1051:                else if (vim_strchr(p_ww, '[') != NULL &&
        !          1052:                                                    curwin->w_cursor.lnum > 1)
        !          1053:                {
        !          1054:                    start_arrow(&tpos);
        !          1055:                    --(curwin->w_cursor.lnum);
        !          1056:                    coladvance(MAXCOL);
        !          1057:                    curwin->w_set_curswant = TRUE;  /* so we stay at the end */
        !          1058:                }
        !          1059:                else
        !          1060:                    beep_flush();
        !          1061:                break;
        !          1062:
        !          1063:              case K_HOME:
        !          1064:                undisplay_dollar();
        !          1065:                tpos = curwin->w_cursor;
        !          1066:                if ((mod_mask & MOD_MASK_CTRL))
        !          1067:                    curwin->w_cursor.lnum = 1;
        !          1068:                curwin->w_cursor.col = 0;
        !          1069:                curwin->w_curswant = 0;
        !          1070:                start_arrow(&tpos);
        !          1071:                break;
        !          1072:
        !          1073:              case K_END:
        !          1074:                undisplay_dollar();
        !          1075:                tpos = curwin->w_cursor;
        !          1076:                if ((mod_mask & MOD_MASK_CTRL))
        !          1077:                    curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          1078:                coladvance(MAXCOL);
        !          1079:                curwin->w_curswant = MAXCOL;
        !          1080:                start_arrow(&tpos);
        !          1081:                break;
        !          1082:
        !          1083:              case K_S_LEFT:
        !          1084:                undisplay_dollar();
        !          1085:                if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
        !          1086:                {
        !          1087:                    start_arrow(&curwin->w_cursor);
        !          1088:                    (void)bck_word(1L, 0, FALSE);
        !          1089:                }
        !          1090:                else
        !          1091:                    beep_flush();
        !          1092:                break;
        !          1093:
        !          1094:              case K_RIGHT:
        !          1095:                undisplay_dollar();
        !          1096:                if (gchar_cursor() != NUL)
        !          1097:                {
        !          1098:                    start_arrow(&curwin->w_cursor);
        !          1099:                    curwin->w_set_curswant = TRUE;
        !          1100:                    ++curwin->w_cursor.col;
        !          1101: #ifdef RIGHTLEFT
        !          1102:                    revinslegal++;
        !          1103:                    if (revinschars)
        !          1104:                        revinschars--;
        !          1105: #endif
        !          1106:                }
        !          1107:                    /* if 'whichwrap' set for cursor in insert mode may go
        !          1108:                     * to next line */
        !          1109:                else if (vim_strchr(p_ww, ']') != NULL &&
        !          1110:                           curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
        !          1111:                {
        !          1112:                    start_arrow(&curwin->w_cursor);
        !          1113:                    curwin->w_set_curswant = TRUE;
        !          1114:                    ++curwin->w_cursor.lnum;
        !          1115:                    curwin->w_cursor.col = 0;
        !          1116:                }
        !          1117:                else
        !          1118:                    beep_flush();
        !          1119:                break;
        !          1120:
        !          1121:              case K_S_RIGHT:
        !          1122:                undisplay_dollar();
        !          1123:                if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count ||
        !          1124:                                                        gchar_cursor() != NUL)
        !          1125:                {
        !          1126:                    start_arrow(&curwin->w_cursor);
        !          1127:                    (void)fwd_word(1L, 0, 0);
        !          1128:                }
        !          1129:                else
        !          1130:                    beep_flush();
        !          1131:                break;
        !          1132:
        !          1133:              case K_UP:
        !          1134:                undisplay_dollar();
        !          1135:                tpos = curwin->w_cursor;
        !          1136:                if (cursor_up(1L) == OK)
        !          1137:                {
        !          1138:                    start_arrow(&tpos);
        !          1139: #ifdef CINDENT
        !          1140:                    can_cindent = TRUE;
        !          1141: #endif
        !          1142:                }
        !          1143:                else
        !          1144:                    beep_flush();
        !          1145:                break;
        !          1146:
        !          1147:              case K_S_UP:
        !          1148:              case K_PAGEUP:
        !          1149:                undisplay_dollar();
        !          1150:                tpos = curwin->w_cursor;
        !          1151:                if (onepage(BACKWARD, 1L) == OK)
        !          1152:                {
        !          1153:                    start_arrow(&tpos);
        !          1154: #ifdef CINDENT
        !          1155:                    can_cindent = TRUE;
        !          1156: #endif
        !          1157:                }
        !          1158:                else
        !          1159:                    beep_flush();
        !          1160:                break;
        !          1161:
        !          1162:              case K_DOWN:
        !          1163:                undisplay_dollar();
        !          1164:                tpos = curwin->w_cursor;
        !          1165:                if (cursor_down(1L) == OK)
        !          1166:                {
        !          1167:                    start_arrow(&tpos);
        !          1168: #ifdef CINDENT
        !          1169:                    can_cindent = TRUE;
        !          1170: #endif
        !          1171:                }
        !          1172:                else
        !          1173:                    beep_flush();
        !          1174:                break;
        !          1175:
        !          1176:              case K_S_DOWN:
        !          1177:              case K_PAGEDOWN:
        !          1178:                undisplay_dollar();
        !          1179:                tpos = curwin->w_cursor;
        !          1180:                if (onepage(FORWARD, 1L) == OK)
        !          1181:                {
        !          1182:                    start_arrow(&tpos);
        !          1183: #ifdef CINDENT
        !          1184:                    can_cindent = TRUE;
        !          1185: #endif
        !          1186:                }
        !          1187:                else
        !          1188:                    beep_flush();
        !          1189:                break;
        !          1190:
        !          1191:              case TAB:             /* TAB or Complete patterns along path */
        !          1192: #ifdef INSERT_EXPAND
        !          1193:                if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
        !          1194:                    goto docomplete;
        !          1195: #endif /* INSERT_EXPAND */
        !          1196:
        !          1197:                if (Insstart_blank_vcol == MAXCOL &&
        !          1198:                                       curwin->w_cursor.lnum == Insstart.lnum)
        !          1199:                    Insstart_blank_vcol = curwin->w_virtcol;
        !          1200:                if (echeck_abbr(TAB + ABBR_OFF))
        !          1201:                    break;
        !          1202:                i = inindent(0);
        !          1203: #ifdef CINDENT
        !          1204:                if (i)
        !          1205:                    can_cindent = FALSE;
        !          1206: #endif
        !          1207:                if (!curbuf->b_p_et && !(p_sta && i))
        !          1208:                    goto normalchar;
        !          1209:
        !          1210:                stop_arrow();
        !          1211:                did_ai = FALSE;
        !          1212:                did_si = FALSE;
        !          1213:                can_si = FALSE;
        !          1214:                can_si_back = FALSE;
        !          1215:                AppendToRedobuff((char_u *)"\t");
        !          1216:
        !          1217:                if (p_sta && i)                 /* insert tab in indent */
        !          1218:                {
        !          1219:                    change_indent(INDENT_INC, 0, p_sr);
        !          1220:                    goto redraw;
        !          1221:                }
        !          1222:
        !          1223:                /*
        !          1224:                 * p_et is set: expand a tab into spaces
        !          1225:                 */
        !          1226:                temp = (int)curbuf->b_p_ts;
        !          1227:                temp -= curwin->w_virtcol % temp;
        !          1228:
        !          1229:                /*
        !          1230:                 * insert the first space with ins_char(); it will delete one
        !          1231:                 * char in replace mode. Insert the rest with ins_str(); it
        !          1232:                 * will not delete any chars
        !          1233:                 */
        !          1234:                ins_char(' ');
        !          1235:                while (--temp)
        !          1236:                {
        !          1237:                    ins_str((char_u *)" ");
        !          1238:                    if (State == REPLACE)       /* no char replaced */
        !          1239:                        replace_push(NUL);
        !          1240:                }
        !          1241:                goto redraw;
        !          1242:
        !          1243:              case CR:
        !          1244:              case NL:
        !          1245:                if (echeck_abbr(c + ABBR_OFF))
        !          1246:                    break;
        !          1247:                stop_arrow();
        !          1248:                if (State == REPLACE)
        !          1249:                    replace_push(NUL);
        !          1250: #ifdef RIGHTLEFT
        !          1251:                /* NL in reverse insert will allways start in the end of
        !          1252:                 * current line. */
        !          1253:                if (revins)
        !          1254:                    while (gchar_cursor() != NUL)
        !          1255:                        ++curwin->w_cursor.col;
        !          1256: #endif
        !          1257:
        !          1258:                AppendToRedobuff(NL_STR);
        !          1259:                if (has_format_option(FO_RET_COMS))
        !          1260:                    fo_do_comments = TRUE;
        !          1261:                i = Opencmd(FORWARD, TRUE, FALSE);
        !          1262:                fo_do_comments = FALSE;
        !          1263: #ifdef CINDENT
        !          1264:                can_cindent = TRUE;
        !          1265: #endif
        !          1266:                if (!i)
        !          1267:                    goto doESCkey;      /* out of memory */
        !          1268:                break;
        !          1269:
        !          1270: #ifdef DIGRAPHS
        !          1271:              case Ctrl('K'):
        !          1272: #ifdef INSERT_EXPAND
        !          1273:                if (ctrl_x_mode == CTRL_X_DICTIONARY)
        !          1274:                    goto docomplete;
        !          1275: #endif
        !          1276:                if (NextScreen != NULL)
        !          1277:                    screen_outchar('?', curwin->w_winpos + curwin->w_row,
        !          1278: #ifdef RIGHTLEFT
        !          1279:                        curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
        !          1280: #endif
        !          1281:                                                            curwin->w_col);
        !          1282:                if (!add_to_showcmd(c, FALSE))
        !          1283:                    setcursor();
        !          1284:                    /* don't map the digraph chars. This also prevents the
        !          1285:                     * mode message to be deleted when ESC is hit */
        !          1286:                ++no_mapping;
        !          1287:                ++allow_keys;
        !          1288:                c = vgetc();
        !          1289:                --no_mapping;
        !          1290:                --allow_keys;
        !          1291:                if (IS_SPECIAL(c))      /* special key */
        !          1292:                {
        !          1293:                    clear_showcmd();
        !          1294:                    insert_special(c, TRUE);
        !          1295:                    need_redraw = TRUE;
        !          1296:                    break;
        !          1297:                }
        !          1298:                if (c != ESC)
        !          1299:                {
        !          1300:                    if (charsize(c) == 1 && NextScreen != NULL)
        !          1301:                        screen_outchar(c, curwin->w_winpos + curwin->w_row,
        !          1302: #ifdef RIGHTLEFT
        !          1303:                            curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
        !          1304: #endif
        !          1305:                                                                curwin->w_col);
        !          1306:                    if (!add_to_showcmd(c, FALSE))
        !          1307:                        setcursor();
        !          1308:                    ++no_mapping;
        !          1309:                    ++allow_keys;
        !          1310:                    cc = vgetc();
        !          1311:                    --no_mapping;
        !          1312:                    --allow_keys;
        !          1313:                    if (cc != ESC)
        !          1314:                    {
        !          1315:                        AppendToRedobuff((char_u *)"\026"); /* CTRL-V */
        !          1316:                        c = getdigraph(c, cc, TRUE);
        !          1317:                        clear_showcmd();
        !          1318:                        goto normalchar;
        !          1319:                    }
        !          1320:                }
        !          1321:                clear_showcmd();
        !          1322:                need_redraw = TRUE;
        !          1323:                break;
        !          1324: #else /* DIGRAPHS */
        !          1325: # ifdef INSERT_EXPAND
        !          1326:              case Ctrl('K'):
        !          1327:                if (ctrl_x_mode != CTRL_X_DICTIONARY)
        !          1328:                    goto normalchar;
        !          1329:                goto docomplete;
        !          1330: # endif /* INSERT_EXPAND */
        !          1331: #endif /* DIGRAPHS */
        !          1332:
        !          1333: #ifdef INSERT_EXPAND
        !          1334:              case Ctrl(']'):           /* Tag name completion after ^X */
        !          1335:                if (ctrl_x_mode != CTRL_X_TAGS)
        !          1336:                    goto normalchar;
        !          1337:                goto docomplete;
        !          1338:
        !          1339:              case Ctrl('F'):           /* File name completion after ^X */
        !          1340:                if (ctrl_x_mode != CTRL_X_FILES)
        !          1341:                    goto normalchar;
        !          1342:                goto docomplete;
        !          1343:
        !          1344:              case Ctrl('L'):           /* Whole line completion after ^X */
        !          1345:                if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
        !          1346:                    goto normalchar;
        !          1347:                /* FALLTHROUGH */
        !          1348:
        !          1349:              case Ctrl('P'):           /* Do previous pattern completion */
        !          1350:              case Ctrl('N'):           /* Do next pattern completion */
        !          1351: docomplete:
        !          1352:                if (c == Ctrl('P') || c == Ctrl('L'))
        !          1353:                    complete_direction = BACKWARD;
        !          1354:                else
        !          1355:                    complete_direction = FORWARD;
        !          1356:                quick_m = mesg = NULL;          /* No message by default */
        !          1357:                if (!started_completion)
        !          1358:                {
        !          1359:                    /* First time we hit ^N or ^P (in a row, I mean) */
        !          1360:
        !          1361:                    /* Turn off 'sm' so we don't show matches with ^X^L */
        !          1362:                    save_sm = p_sm;
        !          1363:                    p_sm = FALSE;
        !          1364:
        !          1365:                    if (ctrl_x_mode == 0)
        !          1366:                    {
        !          1367:                        edit_submode = (char_u *)" Keyword completion (^P/^N)";
        !          1368:                        showmode();
        !          1369:                    }
        !          1370:                    did_ai = FALSE;
        !          1371:                    did_si = FALSE;
        !          1372:                    can_si = FALSE;
        !          1373:                    can_si_back = FALSE;
        !          1374:                    stop_arrow();
        !          1375:                    done_dir = 0;
        !          1376:                    first_match_pos = curwin->w_cursor;
        !          1377:                    ptr = tmp_ptr = ml_get(first_match_pos.lnum);
        !          1378:                    complete_col = first_match_pos.col;
        !          1379:                    temp = (int)complete_col - 1;
        !          1380:
        !          1381:                    /* Work out completion pattern and original text -- webb */
        !          1382:                    if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
        !          1383:                    {
        !          1384:                        if (temp < 0 || !iswordchar(ptr[temp]))
        !          1385:                        {
        !          1386:                            /* Match any word of at least two chars */
        !          1387:                            complete_pat = strsave((char_u *)"\\<\\k\\k");
        !          1388:                            if (complete_pat == NULL)
        !          1389:                                break;
        !          1390:                            tmp_ptr += complete_col;
        !          1391:                            temp = 0;
        !          1392:                        }
        !          1393:                        else
        !          1394:                        {
        !          1395:                            while (temp >= 0 && iswordchar(ptr[temp]))
        !          1396:                                temp--;
        !          1397:                            tmp_ptr += ++temp;
        !          1398:                            if ((temp = (int)complete_col - temp) == 1)
        !          1399:                            {
        !          1400:                                /* Only match word with at least two
        !          1401:                                 * chars -- webb
        !          1402:                                 */
        !          1403:                                sprintf((char *)IObuff, "\\<%c\\k", *tmp_ptr);
        !          1404:                                complete_pat = strsave(IObuff);
        !          1405:                                if (complete_pat == NULL)
        !          1406:                                    break;
        !          1407:                            }
        !          1408:                            else
        !          1409:                            {
        !          1410:                                complete_pat = alloc(temp + 3);
        !          1411:                                if (complete_pat == NULL)
        !          1412:                                    break;
        !          1413:                                sprintf((char *)complete_pat, "\\<%.*s", temp,
        !          1414:                                                                    tmp_ptr);
        !          1415:                            }
        !          1416:                        }
        !          1417:                    }
        !          1418:                    else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
        !          1419:                    {
        !          1420:                        tmp_ptr = skipwhite(ptr);
        !          1421:                        temp = (int)complete_col - (tmp_ptr - ptr);
        !          1422:                        complete_pat = strnsave(tmp_ptr, temp);
        !          1423:                        if (complete_pat == NULL)
        !          1424:                            break;
        !          1425:                    }
        !          1426:                    else if (ctrl_x_mode == CTRL_X_FILES)
        !          1427:                    {
        !          1428:                        while (temp >= 0 && isfilechar(ptr[temp]))
        !          1429:                            temp--;
        !          1430:                        tmp_ptr += ++temp;
        !          1431:                        temp = (int)complete_col - temp;
        !          1432:                        complete_pat = addstar(tmp_ptr, temp);
        !          1433:                        if (complete_pat == NULL)
        !          1434:                            break;
        !          1435:                    }
        !          1436:                    original_text = strnsave(tmp_ptr, temp);
        !          1437:                    if (original_text == NULL)
        !          1438:                    {
        !          1439:                        vim_free(complete_pat);
        !          1440:                        complete_pat = NULL;
        !          1441:                        break;
        !          1442:                    }
        !          1443:
        !          1444:                    complete_col = tmp_ptr - ptr;
        !          1445:                    first_match_pos.col -= temp;
        !          1446:
        !          1447:                    /* So that ^N can match word immediately after cursor */
        !          1448:                    if (ctrl_x_mode == 0)
        !          1449:                        dec(&first_match_pos);
        !          1450:
        !          1451:                    last_match_pos = first_match_pos;
        !          1452:
        !          1453:                    /* Get list of all completions now, if appropriate */
        !          1454:                    if (ctrl_x_mode == CTRL_X_PATH_PATTERNS ||
        !          1455:                        ctrl_x_mode == CTRL_X_PATH_DEFINES)
        !          1456:                    {
        !          1457:                        started_completion = TRUE;
        !          1458:                        find_pattern_in_path(complete_pat,
        !          1459:                                (int)STRLEN(complete_pat), FALSE, FALSE,
        !          1460:                            (ctrl_x_mode == CTRL_X_PATH_DEFINES) ? FIND_DEFINE
        !          1461:                            : FIND_ANY, 1L, ACTION_EXPAND,
        !          1462:                            (linenr_t)1, (linenr_t)MAXLNUM);
        !          1463:
        !          1464:                        if (make_cyclic() > 1)
        !          1465:                        {
        !          1466:                            sprintf((char *)IObuff, "There are %d matches",
        !          1467:                                count_completions());
        !          1468:                            mesg = IObuff;
        !          1469:                        }
        !          1470:                    }
        !          1471:                    else if (ctrl_x_mode == CTRL_X_DICTIONARY)
        !          1472:                    {
        !          1473:                        started_completion = TRUE;
        !          1474:                        if (*p_dict == NUL)
        !          1475:                            mesg = (char_u *)"'dictionary' option is empty";
        !          1476:                        else
        !          1477:                        {
        !          1478:                            complete_dictionaries(complete_pat,
        !          1479:                                                          complete_direction);
        !          1480:                            if (make_cyclic() > 1)
        !          1481:                            {
        !          1482:                                sprintf((char *)IObuff,
        !          1483:                                    "There are %d matching words",
        !          1484:                                    count_completions());
        !          1485:                                mesg = IObuff;
        !          1486:                            }
        !          1487:                        }
        !          1488:                    }
        !          1489:                    else if (ctrl_x_mode == CTRL_X_TAGS)
        !          1490:                    {
        !          1491:                        started_completion = TRUE;
        !          1492:                            /* set reg_ic according to p_ic, p_scs and pat */
        !          1493:                        set_reg_ic(complete_pat);
        !          1494:                        prog = vim_regcomp(complete_pat);
        !          1495:                        if (prog != NULL &&
        !          1496:                            find_tags(NULL, prog, &num_matches, &matches, FALSE)
        !          1497:                                                    == OK && num_matches > 0)
        !          1498:                        {
        !          1499:                            for (i = 0; i < num_matches; i++)
        !          1500:                                if (add_completion(matches[i], -1, NULL,
        !          1501:                                                        FORWARD) == RET_ERROR)
        !          1502:                                    break;
        !          1503:                            FreeWild(num_matches, matches);
        !          1504:                            vim_free(prog);
        !          1505:                            if (make_cyclic() > 1)
        !          1506:                            {
        !          1507:                                sprintf((char *)IObuff,
        !          1508:                                    "There are %d matching tags",
        !          1509:                                    count_completions());
        !          1510:                                mesg = IObuff;
        !          1511:                            }
        !          1512:                        }
        !          1513:                        else
        !          1514:                        {
        !          1515:                            vim_free(prog);
        !          1516:                            vim_free(complete_pat);
        !          1517:                            complete_pat = NULL;
        !          1518:                        }
        !          1519:                    }
        !          1520:                    else if (ctrl_x_mode == CTRL_X_FILES)
        !          1521:                    {
        !          1522:                        started_completion = TRUE;
        !          1523:                        expand_interactively = TRUE;
        !          1524:                        if (ExpandWildCards(1, &complete_pat, &num_matches,
        !          1525:                                                &matches, FALSE, FALSE) == OK)
        !          1526:                        {
        !          1527:                            for (i = 0; i < num_matches; i++)
        !          1528:                                if (add_completion(matches[i], -1, NULL,
        !          1529:                                                        FORWARD) == RET_ERROR)
        !          1530:                                    break;
        !          1531:                            FreeWild(num_matches, matches);
        !          1532:                            if (make_cyclic() > 1)
        !          1533:                            {
        !          1534:                                sprintf((char *)IObuff,
        !          1535:                                    "There are %d matching file names",
        !          1536:                                    count_completions());
        !          1537:                                mesg = IObuff;
        !          1538:                            }
        !          1539:                        }
        !          1540:                        else
        !          1541:                        {
        !          1542:                            vim_free(complete_pat);
        !          1543:                            complete_pat = NULL;
        !          1544:                        }
        !          1545:                        expand_interactively = FALSE;
        !          1546:                    }
        !          1547:                }
        !          1548:                /*
        !          1549:                 * In insert mode: Delete the typed part.
        !          1550:                 * In replace mode: Put the old characters back, if any.
        !          1551:                 */
        !          1552:                while (curwin->w_cursor.col > complete_col)
        !          1553:                {
        !          1554:                    curwin->w_cursor.col--;
        !          1555:                    if (State == REPLACE)
        !          1556:                    {
        !          1557:                        if ((cc = replace_pop()) > 0)
        !          1558:                            pchar(curwin->w_cursor, cc);
        !          1559:                    }
        !          1560:                    else
        !          1561:                        delchar(FALSE);
        !          1562:                }
        !          1563:                complete_pos = NULL;
        !          1564:                if (started_completion && curr_match == NULL &&
        !          1565:                                        (p_ws || done_dir == BOTH_DIRECTIONS))
        !          1566:                    quick_m = e_patnotf;
        !          1567:                else if (curr_match != NULL && complete_direction == FORWARD &&
        !          1568:                                            curr_match->next != NULL)
        !          1569:                    curr_match = curr_match->next;
        !          1570:                else if (curr_match != NULL && complete_direction == BACKWARD &&
        !          1571:                                            curr_match->prev != NULL)
        !          1572:                    curr_match = curr_match->prev;
        !          1573:                else
        !          1574:                {
        !          1575:                    complete_pos = (complete_direction == FORWARD) ?
        !          1576:                                        &last_match_pos : &first_match_pos;
        !          1577:                    /*
        !          1578:                     * If 'infercase' is set, don't use 'smartcase' here
        !          1579:                     */
        !          1580:                    save_p_scs = p_scs;
        !          1581:                    if (curbuf->b_p_inf)
        !          1582:                        p_scs = FALSE;
        !          1583:                    for (;;)
        !          1584:                    {
        !          1585:                        if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
        !          1586:                            temp = search_for_exact_line(complete_pos,
        !          1587:                                    complete_direction, complete_pat);
        !          1588:                        else
        !          1589:                            temp = searchit(complete_pos, complete_direction,
        !          1590:                                    complete_pat, 1L,
        !          1591:                                    SEARCH_KEEP + SEARCH_NFMSG, RE_LAST);
        !          1592:                        if (temp == FAIL)
        !          1593:                        {
        !          1594:                            if (!p_ws && done_dir != -complete_direction)
        !          1595:                            {
        !          1596:                                /*
        !          1597:                                 * With nowrapscan, we haven't finished
        !          1598:                                 * looking in the other direction yet -- webb
        !          1599:                                 */
        !          1600:                                temp = OK;
        !          1601:                                done_dir = complete_direction;
        !          1602:                            }
        !          1603:                            else if (!p_ws)
        !          1604:                                done_dir = BOTH_DIRECTIONS;
        !          1605:                            break;
        !          1606:                        }
        !          1607:                        if (!started_completion)
        !          1608:                        {
        !          1609:                            started_completion = TRUE;
        !          1610:                            first_match_pos = *complete_pos;
        !          1611:                            last_match_pos = *complete_pos;
        !          1612:                        }
        !          1613:                        else if (first_match_pos.lnum == last_match_pos.lnum &&
        !          1614:                          first_match_pos.col == last_match_pos.col)
        !          1615:                        {
        !          1616:                            /* We have found all the matches in this file */
        !          1617:                            temp = FAIL;
        !          1618:                            break;
        !          1619:                        }
        !          1620:                        ptr = ml_get_pos(complete_pos);
        !          1621:                        if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
        !          1622:                            temp = STRLEN(ptr);
        !          1623:                        else
        !          1624:                        {
        !          1625:                            tmp_ptr = ptr;
        !          1626:                            temp = 0;
        !          1627:                            while (*tmp_ptr != NUL && iswordchar(*tmp_ptr++))
        !          1628:                                temp++;
        !          1629:                        }
        !          1630:                        if (add_completion_and_infercase(ptr, temp, NULL,
        !          1631:                                                  complete_direction) != FAIL)
        !          1632:                        {
        !          1633:                            temp = OK;
        !          1634:                            break;
        !          1635:                        }
        !          1636:                    }
        !          1637:                    p_scs = save_p_scs;
        !          1638:                }
        !          1639:                if (complete_pos != NULL && temp == FAIL)
        !          1640:                {
        !          1641:                    int tot;
        !          1642:
        !          1643:                    tot = count_completions();  /* Total num matches */
        !          1644:                    if (curr_match != NULL)
        !          1645:                        (void)make_cyclic();
        !          1646:                    if (tot > 1)
        !          1647:                    {
        !          1648:                        sprintf((char *)IObuff,
        !          1649:                            "All %d matches have now been found", tot);
        !          1650:                        mesg = IObuff;
        !          1651:                    }
        !          1652:                    else if (tot == 0)
        !          1653:                        quick_m = e_patnotf;
        !          1654:                }
        !          1655:
        !          1656:                /* eat the ESC to avoid leaving insert mode */
        !          1657:                if (got_int)
        !          1658:                {
        !          1659:                    (void)vgetc();
        !          1660:                    got_int = FALSE;
        !          1661:                }
        !          1662:
        !          1663:                /*
        !          1664:                 * When using match from another file, show the file name.
        !          1665:                 */
        !          1666:                if (curr_match != NULL)
        !          1667:                    ptr = curr_match->str;
        !          1668:                else            /* back to what has been typed */
        !          1669:                    ptr = original_text;
        !          1670:
        !          1671:                if (curr_match == NULL || curr_match->original)
        !          1672:                {
        !          1673:                    edit_submode_extra = (char_u *)"Back at original";
        !          1674:                    edit_submode_highl = TRUE;
        !          1675:                }
        !          1676:                else if (first_match != NULL && first_match->next != NULL &&
        !          1677:                                          (first_match->next == first_match ||
        !          1678:                                                  first_match->next->original))
        !          1679:                {
        !          1680:                    edit_submode_extra = (char_u *)"(the only match)";
        !          1681:                    edit_submode_highl = FALSE;
        !          1682:                }
        !          1683:
        !          1684:                /*
        !          1685:                 * Use ins_char() to insert the text, it is a bit slower than
        !          1686:                 * ins_str(), but it takes care of replace mode.
        !          1687:                 */
        !          1688:                if (ptr != NULL)
        !          1689:                    while (*ptr)
        !          1690:                        ins_char(*ptr++);
        !          1691:
        !          1692:                started_completion = TRUE;
        !          1693:                need_redraw = TRUE;
        !          1694:                (void)set_highlight('r');
        !          1695:                msg_highlight = TRUE;
        !          1696:                if (mesg != NULL)
        !          1697:                {
        !          1698:                    msg(mesg);
        !          1699:                    mch_delay(1000L, FALSE);
        !          1700:                }
        !          1701:                else if (quick_m != NULL)
        !          1702:                    msg(quick_m);
        !          1703:                else if (edit_submode_extra != NULL)
        !          1704:                    showmode();
        !          1705:                edit_submode_extra = NULL;
        !          1706:                msg_highlight = FALSE;
        !          1707:
        !          1708:                /*
        !          1709:                 * If there is a file name for the match, overwrite any
        !          1710:                 * previous message, it's more interesting to know where the
        !          1711:                 * match comes from, except when using the dictionary.
        !          1712:                 * Truncate the file name to avoid a wait for return.
        !          1713:                 */
        !          1714:                if (curr_match != NULL && curr_match->fname != NULL &&
        !          1715:                            (ctrl_x_mode != CTRL_X_DICTIONARY ||
        !          1716:                                           (mesg == NULL && quick_m == NULL)))
        !          1717:                {
        !          1718:                    STRCPY(IObuff, "match in file ");
        !          1719:                    i = (strsize(curr_match->fname) + 16) - sc_col;
        !          1720:                    if (i <= 0)
        !          1721:                        i = 0;
        !          1722:                    else
        !          1723:                        STRCAT(IObuff, "<");
        !          1724:                    STRCAT(IObuff, curr_match->fname + i);
        !          1725:                    msg(IObuff);
        !          1726:                }
        !          1727:                break;
        !          1728: #endif /* INSERT_EXPAND */
        !          1729:
        !          1730:              case Ctrl('Y'):               /* copy from previous line */
        !          1731: #ifdef INSERT_EXPAND
        !          1732:                if (ctrl_x_mode == CTRL_X_SCROLL)
        !          1733:                {
        !          1734:                    scrolldown_clamp();
        !          1735:                    updateScreen(VALID);
        !          1736:                    break;
        !          1737:                }
        !          1738: #endif /* INSERT_EXPAND */
        !          1739:                lnum = curwin->w_cursor.lnum - 1;
        !          1740:                goto copychar;
        !          1741:
        !          1742:              case Ctrl('E'):               /* copy from next line */
        !          1743: #ifdef INSERT_EXPAND
        !          1744:                if (ctrl_x_mode == CTRL_X_SCROLL)
        !          1745:                {
        !          1746:                    scrollup_clamp();
        !          1747:                    updateScreen(VALID);
        !          1748:                    break;
        !          1749:                }
        !          1750: #endif /* INSERT_EXPAND */
        !          1751:                lnum = curwin->w_cursor.lnum + 1;
        !          1752: copychar:
        !          1753:                if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
        !          1754:                {
        !          1755:                    beep_flush();
        !          1756:                    break;
        !          1757:                }
        !          1758:
        !          1759:                /* try to advance to the cursor column */
        !          1760:                temp = 0;
        !          1761:                ptr = ml_get(lnum);
        !          1762:                while ((colnr_t)temp < curwin->w_virtcol && *ptr)
        !          1763:                    temp += lbr_chartabsize(ptr++, (colnr_t)temp);
        !          1764:
        !          1765:                if ((colnr_t)temp > curwin->w_virtcol)
        !          1766:                    --ptr;
        !          1767:                if ((c = *ptr) == NUL)
        !          1768:                {
        !          1769:                    beep_flush();
        !          1770:                    break;
        !          1771:                }
        !          1772:
        !          1773:                /*FALLTHROUGH*/
        !          1774:              default:
        !          1775: normalchar:
        !          1776:                /*
        !          1777:                 * do some very smart indenting when entering '{' or '}'
        !          1778:                 */
        !          1779:                if (((did_si || can_si_back) && c == '{') ||
        !          1780:                                                         (can_si && c == '}'))
        !          1781:                {
        !          1782:                    FPOS    *pos, old_pos;
        !          1783:
        !          1784:                        /* for '}' set indent equal to indent of line
        !          1785:                         * containing matching '{'
        !          1786:                         */
        !          1787:                    if (c == '}' && (pos = findmatch('{')) != NULL)
        !          1788:                    {
        !          1789:                        old_pos = curwin->w_cursor;
        !          1790:                        /*
        !          1791:                         * If the matching '{' has a ')' immediately before it
        !          1792:                         * (ignoring white-space), then line up with the start
        !          1793:                         * of the line containing the matching '(' if there is
        !          1794:                         * one.  This handles the case where an
        !          1795:                         * "if (..\n..) {" statement continues over multiple
        !          1796:                         * lines -- webb
        !          1797:                         */
        !          1798:                        ptr = ml_get(pos->lnum);
        !          1799:                        i = pos->col;
        !          1800:                        if (i > 0)          /* skip blanks before '{' */
        !          1801:                            while (--i > 0 && vim_iswhite(ptr[i]))
        !          1802:                                ;
        !          1803:                        curwin->w_cursor.lnum = pos->lnum;
        !          1804:                        curwin->w_cursor.col = i;
        !          1805:                        if (ptr[i] == ')' && (pos = findmatch('(')) != NULL)
        !          1806:                            curwin->w_cursor = *pos;
        !          1807:                        i = get_indent();
        !          1808:                        curwin->w_cursor = old_pos;
        !          1809:                        set_indent(i, TRUE);
        !          1810:                    }
        !          1811:                    else if (curwin->w_cursor.col > 0)
        !          1812:                    {
        !          1813:                        /*
        !          1814:                         * when inserting '{' after "O" reduce indent, but not
        !          1815:                         * more than indent of previous line
        !          1816:                         */
        !          1817:                        temp = TRUE;
        !          1818:                        if (c == '{' && can_si_back &&
        !          1819:                                                    curwin->w_cursor.lnum > 1)
        !          1820:                        {
        !          1821:                            old_pos = curwin->w_cursor;
        !          1822:                            i = get_indent();
        !          1823:                            while (curwin->w_cursor.lnum > 1)
        !          1824:                            {
        !          1825:                                ptr = skipwhite(
        !          1826:                                           ml_get(--(curwin->w_cursor.lnum)));
        !          1827:                                /* ignore empty lines and lines starting with
        !          1828:                                 * '#'.
        !          1829:                                 */
        !          1830:                                if (*ptr != '#' && *ptr != NUL)
        !          1831:                                    break;
        !          1832:                            }
        !          1833:                            if (get_indent() >= i)
        !          1834:                                temp = FALSE;
        !          1835:                            curwin->w_cursor = old_pos;
        !          1836:                        }
        !          1837:                        if (temp)
        !          1838:                            shift_line(TRUE, FALSE, 1);
        !          1839:                    }
        !          1840:                }
        !          1841:                    /* set indent of '#' always to 0 */
        !          1842:                if (curwin->w_cursor.col > 0 && can_si && c == '#')
        !          1843:                {
        !          1844:                                /* remember current indent for next line */
        !          1845:                    old_indent = get_indent();
        !          1846:                    set_indent(0, TRUE);
        !          1847:                }
        !          1848:
        !          1849:                if (c == ' ')
        !          1850:                {
        !          1851: #ifdef CINDENT
        !          1852:                    if (inindent(0))
        !          1853:                        can_cindent = FALSE;
        !          1854: #endif
        !          1855:                    if (Insstart_blank_vcol == MAXCOL &&
        !          1856:                                       curwin->w_cursor.lnum == Insstart.lnum)
        !          1857:                        Insstart_blank_vcol = curwin->w_virtcol;
        !          1858:                }
        !          1859:
        !          1860:                if (iswordchar(c) || !echeck_abbr(c))
        !          1861:                {
        !          1862:                    insert_special(c, FALSE);
        !          1863:                    need_redraw = TRUE;
        !          1864: #ifdef RIGHTLEFT
        !          1865:                    revinslegal++;
        !          1866:                    revinschars++;
        !          1867: #endif
        !          1868:                }
        !          1869:                break;
        !          1870:        }   /* end of switch (c) */
        !          1871:
        !          1872: #ifdef CINDENT
        !          1873:        if (curbuf->b_p_cin && can_cindent
        !          1874: # ifdef INSERT_EXPAND
        !          1875:                                            && !ctrl_x_mode
        !          1876: # endif
        !          1877:                                                               )
        !          1878:        {
        !          1879: force_cindent:
        !          1880:            /*
        !          1881:             * Indent now if a key was typed that is in 'cinkeys'.
        !          1882:             */
        !          1883:            if (in_cinkeys(c, ' ', line_is_white))
        !          1884:            {
        !          1885:                stop_arrow();
        !          1886:
        !          1887:                /* re-indent the current line */
        !          1888:                fixthisline(get_c_indent);
        !          1889:
        !          1890:                /* draw the changes on the screen later */
        !          1891:                need_redraw = TRUE;
        !          1892:            }
        !          1893:        }
        !          1894: #endif /* CINDENT */
        !          1895:
        !          1896:    }   /* for (;;) */
        !          1897: }
        !          1898:
        !          1899: /*
        !          1900:  * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
        !          1901:  * Keep the cursor on the same character.
        !          1902:  * type == INDENT_INC  increase indent (for CTRL-T or <Tab>)
        !          1903:  * type == INDENT_DEC  decrease indent (for CTRL-D)
        !          1904:  * type == INDENT_SET  set indent to "amount"
        !          1905:  * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
        !          1906:  */
        !          1907:    static void
        !          1908: change_indent(type, amount, round)
        !          1909:    int     type;
        !          1910:    int     amount;
        !          1911:    int     round;
        !          1912: {
        !          1913:    int         vcol;
        !          1914:    int         last_vcol;
        !          1915:    int         insstart_less;          /* reduction for Insstart.col */
        !          1916:    int         new_cursor_col;
        !          1917:    int         i;
        !          1918:    char_u      *ptr;
        !          1919:    int         save_p_list;
        !          1920:
        !          1921:    /* for the following tricks we don't want list mode */
        !          1922:    save_p_list = curwin->w_p_list;
        !          1923:     if (save_p_list)
        !          1924:     {
        !          1925:         curwin->w_p_list = FALSE;
        !          1926:         curs_columns(FALSE);           /* recompute w_virtcol */
        !          1927:     }
        !          1928:    vcol = curwin->w_virtcol;
        !          1929:
        !          1930:    /* determine offset from first non-blank */
        !          1931:    new_cursor_col = curwin->w_cursor.col;
        !          1932:    beginline(TRUE);
        !          1933:    new_cursor_col -= curwin->w_cursor.col;
        !          1934:
        !          1935:    insstart_less = curwin->w_cursor.col;
        !          1936:
        !          1937:    /*
        !          1938:     * If the cursor is in the indent, compute how many screen columns the
        !          1939:     * cursor is to the left of the first non-blank.
        !          1940:     */
        !          1941:    if (new_cursor_col < 0)
        !          1942:        vcol = get_indent() - vcol;
        !          1943:
        !          1944:    /*
        !          1945:     * Set the new indent.  The cursor will be put on the first non-blank.
        !          1946:     */
        !          1947:    if (type == INDENT_SET)
        !          1948:        set_indent(amount, TRUE);
        !          1949:    else
        !          1950:        shift_line(type == INDENT_DEC, round, 1);
        !          1951:    insstart_less -= curwin->w_cursor.col;
        !          1952:
        !          1953:    /*
        !          1954:     * Try to put cursor on same character.
        !          1955:     * If the cursor is at or after the first non-blank in the line,
        !          1956:     * compute the cursor column relative to the column of the first
        !          1957:     * non-blank character.
        !          1958:     * If we are not in insert mode, leave the cursor on the first non-blank.
        !          1959:     * If the cursor is before the first non-blank, position it relative
        !          1960:     * to the first non-blank, counted in screen columns.
        !          1961:     */
        !          1962:    if (new_cursor_col >= 0)
        !          1963:        new_cursor_col += curwin->w_cursor.col;
        !          1964:    else if (!(State & INSERT))
        !          1965:        new_cursor_col = curwin->w_cursor.col;
        !          1966:    else
        !          1967:    {
        !          1968:        /*
        !          1969:         * Compute the screen column where the cursor should be.
        !          1970:         */
        !          1971:        vcol = get_indent() - vcol;
        !          1972:        curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
        !          1973:
        !          1974:        /*
        !          1975:         * Advance the cursor until we reach the right screen column.
        !          1976:         */
        !          1977:        vcol = last_vcol = 0;
        !          1978:        new_cursor_col = -1;
        !          1979:        ptr = ml_get_curline();
        !          1980:        while (vcol <= (int)curwin->w_virtcol)
        !          1981:        {
        !          1982:            last_vcol = vcol;
        !          1983:            ++new_cursor_col;
        !          1984:            vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_t)vcol);
        !          1985:        }
        !          1986:        vcol = last_vcol;
        !          1987:
        !          1988:        /*
        !          1989:         * May need to insert spaces to be able to position the cursor on
        !          1990:         * the right screen column.
        !          1991:         */
        !          1992:        if (vcol != (int)curwin->w_virtcol)
        !          1993:        {
        !          1994:            curwin->w_cursor.col = new_cursor_col;
        !          1995:            i = (int)curwin->w_virtcol - vcol;
        !          1996:            ptr = alloc(i + 1);
        !          1997:            if (ptr != NULL)
        !          1998:            {
        !          1999:                new_cursor_col += i;
        !          2000:                ptr[i] = NUL;
        !          2001:                while (--i >= 0)
        !          2002:                    ptr[i] = ' ';
        !          2003:                ins_str(ptr);
        !          2004:                vim_free(ptr);
        !          2005:            }
        !          2006:        }
        !          2007:
        !          2008:        /*
        !          2009:         * When changing the indent while the cursor is in it, reset
        !          2010:         * Insstart_col to 0.
        !          2011:         */
        !          2012:        insstart_less = Insstart.col;
        !          2013:    }
        !          2014:
        !          2015:    curwin->w_p_list = save_p_list;
        !          2016:
        !          2017:    if (new_cursor_col <= 0)
        !          2018:        curwin->w_cursor.col = 0;
        !          2019:    else
        !          2020:        curwin->w_cursor.col = new_cursor_col;
        !          2021:    curwin->w_set_curswant = TRUE;
        !          2022:
        !          2023:    /*
        !          2024:     * May have to adjust the start of the insert.
        !          2025:     */
        !          2026:    if ((State & INSERT) && curwin->w_cursor.lnum == Insstart.lnum &&
        !          2027:                                                            Insstart.col != 0)
        !          2028:    {
        !          2029:        if ((int)Insstart.col <= insstart_less)
        !          2030:            Insstart.col = 0;
        !          2031:        else
        !          2032:            Insstart.col -= insstart_less;
        !          2033:    }
        !          2034: }
        !          2035:
        !          2036: #ifdef INSERT_EXPAND
        !          2037: /*
        !          2038:  * Is the character 'c' a valid key to keep us in the current ctrl-x mode?
        !          2039:  * -- webb
        !          2040:  */
        !          2041:    int
        !          2042: is_ctrl_x_key(c)
        !          2043:    int     c;
        !          2044: {
        !          2045:    switch (ctrl_x_mode)
        !          2046:    {
        !          2047:        case 0:             /* Not in any ctrl-x mode */
        !          2048:            break;
        !          2049:        case CTRL_X_NOT_DEFINED_YET:
        !          2050:            if (c == Ctrl('X') || c == Ctrl('Y') || c == Ctrl('E') ||
        !          2051:                    c == Ctrl('L') || c == Ctrl('F') || c == Ctrl(']') ||
        !          2052:                    c == Ctrl('I') || c == Ctrl('D') || c == Ctrl('P') ||
        !          2053:                    c == Ctrl('N'))
        !          2054:                return TRUE;
        !          2055:            break;
        !          2056:        case CTRL_X_SCROLL:
        !          2057:            if (c == Ctrl('Y') || c == Ctrl('E'))
        !          2058:                return TRUE;
        !          2059:            break;
        !          2060:        case CTRL_X_WHOLE_LINE:
        !          2061:            if (c == Ctrl('L') || c == Ctrl('P') || c == Ctrl('N'))
        !          2062:                return TRUE;
        !          2063:            break;
        !          2064:        case CTRL_X_FILES:
        !          2065:            if (c == Ctrl('F') || c == Ctrl('P') || c == Ctrl('N'))
        !          2066:                return TRUE;
        !          2067:            break;
        !          2068:        case CTRL_X_DICTIONARY:
        !          2069:            if (c == Ctrl('K') || c == Ctrl('P') || c == Ctrl('N'))
        !          2070:                return TRUE;
        !          2071:            break;
        !          2072:        case CTRL_X_TAGS:
        !          2073:            if (c == Ctrl(']') || c == Ctrl('P') || c == Ctrl('N'))
        !          2074:                return TRUE;
        !          2075:            break;
        !          2076:        case CTRL_X_PATH_PATTERNS:
        !          2077:            if (c == Ctrl('P') || c == Ctrl('N'))
        !          2078:                return TRUE;
        !          2079:            break;
        !          2080:        case CTRL_X_PATH_DEFINES:
        !          2081:            if (c == Ctrl('D') || c == Ctrl('P') || c == Ctrl('N'))
        !          2082:                return TRUE;
        !          2083:            break;
        !          2084:        default:
        !          2085:            emsg(e_internal);
        !          2086:            break;
        !          2087:    }
        !          2088:    return FALSE;
        !          2089: }
        !          2090:
        !          2091: /*
        !          2092:  * This is like add_completion(), but if ic and inf are set, then the
        !          2093:  * case of the originally typed text is used, and the case of the completed
        !          2094:  * text is infered, ie this tries to work out what case you probably wanted
        !          2095:  * the rest of the word to be in -- webb
        !          2096:  */
        !          2097:    int
        !          2098: add_completion_and_infercase(str, len, fname, dir)
        !          2099:    char_u  *str;
        !          2100:    int     len;
        !          2101:    char_u  *fname;
        !          2102:    int     dir;
        !          2103: {
        !          2104:    int has_lower = FALSE;
        !          2105:    int was_letter = FALSE;
        !          2106:    int orig_len;
        !          2107:    int idx;
        !          2108:
        !          2109:    if (p_ic && curbuf->b_p_inf && len < IOSIZE)
        !          2110:    {
        !          2111:        /* Infer case of completed part -- webb */
        !          2112:        orig_len = STRLEN(original_text);
        !          2113:
        !          2114:        /* Use IObuff, str would change text in buffer! */
        !          2115:        STRNCPY(IObuff, str, len);
        !          2116:        IObuff[len] = NUL;
        !          2117:
        !          2118:        /* Rule 1: Were any chars converted to lower? */
        !          2119:        for (idx = 0; idx < orig_len; ++idx)
        !          2120:        {
        !          2121:            if (islower(original_text[idx]))
        !          2122:            {
        !          2123:                has_lower = TRUE;
        !          2124:                if (isupper(IObuff[idx]))
        !          2125:                {
        !          2126:                    /* Rule 1 is satisfied */
        !          2127:                    for (idx = orig_len; idx < len; ++idx)
        !          2128:                        IObuff[idx] = TO_LOWER(IObuff[idx]);
        !          2129:                    break;
        !          2130:                }
        !          2131:            }
        !          2132:        }
        !          2133:
        !          2134:        /*
        !          2135:         * Rule 2: No lower case, 2nd consecutive letter converted to
        !          2136:         * upper case.
        !          2137:         */
        !          2138:        if (!has_lower)
        !          2139:        {
        !          2140:            for (idx = 0; idx < orig_len; ++idx)
        !          2141:            {
        !          2142:                if (was_letter && isupper(original_text[idx]) &&
        !          2143:                    islower(IObuff[idx]))
        !          2144:                {
        !          2145:                    /* Rule 2 is satisfied */
        !          2146:                    for (idx = orig_len; idx < len; ++idx)
        !          2147:                        IObuff[idx] = TO_UPPER(IObuff[idx]);
        !          2148:                    break;
        !          2149:                }
        !          2150:                was_letter = isalpha(original_text[idx]);
        !          2151:            }
        !          2152:        }
        !          2153:
        !          2154:        /* Copy the original case of the part we typed */
        !          2155:        STRNCPY(IObuff, original_text, orig_len);
        !          2156:
        !          2157:        return add_completion(IObuff, len, fname, dir);
        !          2158:    }
        !          2159:    return add_completion(str, len, fname, dir);
        !          2160: }
        !          2161:
        !          2162: /*
        !          2163:  * Add a match to the list of matches.
        !          2164:  * If the given string is already in the list of completions, then return
        !          2165:  * FAIL, otherwise add it to the list and return OK.  If there is an error,
        !          2166:  * maybe because alloc returns NULL, then RET_ERROR is returned -- webb.
        !          2167:  */
        !          2168:    static int
        !          2169: add_completion(str, len, fname, dir)
        !          2170:    char_u  *str;
        !          2171:    int     len;
        !          2172:    char_u  *fname;
        !          2173:    int     dir;
        !          2174: {
        !          2175:    struct Completion *match;
        !          2176:
        !          2177:    mch_breakcheck();
        !          2178:    if (got_int)
        !          2179:        return RET_ERROR;
        !          2180:    if (len < 0)
        !          2181:        len = STRLEN(str);
        !          2182:
        !          2183:    /*
        !          2184:     * If the same match is already present, don't add it.
        !          2185:     */
        !          2186:    if (first_match != NULL)
        !          2187:    {
        !          2188:        match = first_match;
        !          2189:        do
        !          2190:        {
        !          2191:            if (STRNCMP(match->str, str, (size_t)len) == 0 &&
        !          2192:                                                       match->str[len] == NUL)
        !          2193:                return FAIL;
        !          2194:            match = match->next;
        !          2195:        } while (match != NULL && match != first_match);
        !          2196:    }
        !          2197:
        !          2198:    /*
        !          2199:     * Allocate a new match structure.
        !          2200:     * Copy the values to the new match structure.
        !          2201:     */
        !          2202:    match = (struct Completion *)alloc((unsigned)sizeof(struct Completion));
        !          2203:    if (match == NULL)
        !          2204:        return RET_ERROR;
        !          2205:    if ((match->str = strnsave(str, len)) == NULL)
        !          2206:    {
        !          2207:        vim_free(match);
        !          2208:        return RET_ERROR;
        !          2209:    }
        !          2210:    if (fname != NULL)
        !          2211:        match->fname = strsave(fname);      /* ignore errors */
        !          2212:    else
        !          2213:        match->fname = NULL;
        !          2214:    match->original = FALSE;
        !          2215:
        !          2216:    /*
        !          2217:     * Link the new match structure in the list of matches.
        !          2218:     */
        !          2219:    if (first_match == NULL)
        !          2220:    {
        !          2221:        first_match = curr_match = match;
        !          2222:        curr_match->next = curr_match->prev = NULL;
        !          2223:    }
        !          2224:    else
        !          2225:    {
        !          2226:        if (dir == FORWARD)
        !          2227:        {
        !          2228:            match->next = NULL;
        !          2229:            match->prev = curr_match;
        !          2230:            curr_match->next = match;
        !          2231:            curr_match = match;
        !          2232:        }
        !          2233:        else    /* BACKWARD */
        !          2234:        {
        !          2235:            match->prev = NULL;
        !          2236:            match->next = curr_match;
        !          2237:            curr_match->prev = match;
        !          2238:            first_match = curr_match = match;
        !          2239:        }
        !          2240:    }
        !          2241:
        !          2242:    return OK;
        !          2243: }
        !          2244:
        !          2245: /*
        !          2246:  * Make the completion list cyclic.  Add the original text at the end.
        !          2247:  * Return the number of matches (excluding the original).
        !          2248:  */
        !          2249:    static int
        !          2250: make_cyclic()
        !          2251: {
        !          2252:    struct Completion *match, *orig;
        !          2253:    int     count = 0;
        !          2254:
        !          2255:    if (first_match != NULL)
        !          2256:    {
        !          2257:        /*
        !          2258:         * Find the end of the list.
        !          2259:         */
        !          2260:        match = first_match;
        !          2261:        count = 1;
        !          2262:        while (match->next != NULL)
        !          2263:        {
        !          2264:            match = match->next;
        !          2265:            ++count;
        !          2266:        }
        !          2267:
        !          2268:        if (original_text != NULL)
        !          2269:        {
        !          2270:            /*
        !          2271:             * Allocate a new structure for the original text.
        !          2272:             * Copy the original text to the new structure.
        !          2273:             * Link it in the list at the end.
        !          2274:             */
        !          2275:            orig = (struct Completion *)alloc((unsigned)sizeof(
        !          2276:                                                          struct Completion));
        !          2277:            if (orig != NULL)
        !          2278:            {
        !          2279:                if ((orig->str = strsave(original_text)) == NULL)
        !          2280:                    vim_free(orig);
        !          2281:                else
        !          2282:                {
        !          2283:                    orig->fname = NULL;
        !          2284:                    orig->original = TRUE;
        !          2285:                    orig->prev = match;
        !          2286:                    match->next = orig;
        !          2287:                    match = orig;
        !          2288:                    curr_match = orig;
        !          2289:                }
        !          2290:            }
        !          2291:        }
        !          2292:        match->next = first_match;
        !          2293:        first_match->prev = match;
        !          2294:    }
        !          2295:    return count;
        !          2296: }
        !          2297:
        !          2298: /*
        !          2299:  * Add any identifiers that match the given pattern to the list of
        !          2300:  * completions.
        !          2301:  */
        !          2302:    static void
        !          2303: complete_dictionaries(pat, dir)
        !          2304:    char_u  *pat;
        !          2305:    int     dir;
        !          2306: {
        !          2307:    struct Completion *save_curr_match = curr_match;
        !          2308:    char_u  *dict = p_dict;
        !          2309:    char_u  *ptr;
        !          2310:    char_u  *buf;
        !          2311:    char_u  *fname;
        !          2312:    int     at_start;
        !          2313:    FILE    *fp;
        !          2314:    struct regexp *prog = NULL;
        !          2315:
        !          2316:    if ((buf = alloc(LSIZE)) == NULL)
        !          2317:        return;
        !          2318:    if (curr_match != NULL)
        !          2319:    {
        !          2320:        while (curr_match->next != NULL)
        !          2321:            curr_match = curr_match->next;
        !          2322:    }
        !          2323:    if (*dict != NUL)
        !          2324:    {
        !          2325:        (void)set_highlight('r');
        !          2326:        msg_highlight = TRUE;
        !          2327:        MSG("Please wait, searching dictionaries");
        !          2328:        set_reg_ic(pat);    /* set reg_ic according to p_ic, p_scs and pat */
        !          2329:        reg_magic = p_magic;
        !          2330:        prog = vim_regcomp(pat);
        !          2331:    }
        !          2332:    while (*dict != NUL && prog != NULL && !got_int)
        !          2333:    {
        !          2334:                                /* copy one dictionary file name into buf */
        !          2335:        (void)copy_option_part(&dict, buf, LSIZE, ",");
        !          2336:
        !          2337:        fp = fopen((char *)buf, "r");       /* open dictionary file */
        !          2338:
        !          2339:        if (fp != NULL)
        !          2340:        {
        !          2341:            fname = strsave(buf);           /* keep name of file */
        !          2342:            /*
        !          2343:             * Read dictionary file line by line.
        !          2344:             * Check each line for a match.
        !          2345:             */
        !          2346:            while (!got_int && !vim_fgets(buf, LSIZE, fp))
        !          2347:            {
        !          2348:                ptr = buf;
        !          2349:                at_start = TRUE;
        !          2350:                while (vim_regexec(prog, ptr, at_start))
        !          2351:                {
        !          2352:                    at_start = FALSE;
        !          2353:                    ptr = prog->startp[0];
        !          2354:                    while (iswordchar(*ptr))
        !          2355:                        ++ptr;
        !          2356:                    if (add_completion_and_infercase(prog->startp[0],
        !          2357:                                 (int)(ptr - prog->startp[0]), fname, FORWARD)
        !          2358:                                                                 == RET_ERROR)
        !          2359:                        break;
        !          2360:                }
        !          2361:                line_breakcheck();
        !          2362:            }
        !          2363:            fclose(fp);
        !          2364:            vim_free(fname);
        !          2365:        }
        !          2366:    }
        !          2367:    vim_free(prog);
        !          2368:    if (save_curr_match != NULL)
        !          2369:        curr_match = save_curr_match;
        !          2370:    else if (dir == BACKWARD)
        !          2371:        curr_match = first_match;
        !          2372:    vim_free(buf);
        !          2373: }
        !          2374:
        !          2375: /*
        !          2376:  * Free the list of completions
        !          2377:  */
        !          2378:    static void
        !          2379: free_completions()
        !          2380: {
        !          2381:    struct Completion *match;
        !          2382:
        !          2383:    if (first_match == NULL)
        !          2384:        return;
        !          2385:    curr_match = first_match;
        !          2386:    do
        !          2387:    {
        !          2388:        match = curr_match;
        !          2389:        curr_match = curr_match->next;
        !          2390:        vim_free(match->str);
        !          2391:        vim_free(match->fname);
        !          2392:        vim_free(match);
        !          2393:    } while (curr_match != NULL && curr_match != first_match);
        !          2394:    first_match = curr_match = NULL;
        !          2395: }
        !          2396:
        !          2397: /*
        !          2398:  * Return the number of items in the Completion list
        !          2399:  */
        !          2400:    static int
        !          2401: count_completions()
        !          2402: {
        !          2403:    struct Completion *match;
        !          2404:    int num = 0;
        !          2405:
        !          2406:    if (first_match == NULL)
        !          2407:        return 0;
        !          2408:    match = first_match;
        !          2409:    do
        !          2410:    {
        !          2411:        if (!match->original)       /* original string doesn't count */
        !          2412:            num++;
        !          2413:        match = match->next;
        !          2414:    } while (match != NULL && match != first_match);
        !          2415:    return num;
        !          2416: }
        !          2417: #endif /* INSERT_EXPAND */
        !          2418:
        !          2419: /*
        !          2420:  * Next character is interpreted literally.
        !          2421:  * A one, two or three digit decimal number is interpreted as its byte value.
        !          2422:  * If one or two digits are entered, the next character is given to vungetc().
        !          2423:  */
        !          2424:    int
        !          2425: get_literal()
        !          2426: {
        !          2427:    int          cc;
        !          2428:    int          nc;
        !          2429:    int          i;
        !          2430:
        !          2431:    if (got_int)
        !          2432:        return Ctrl('C');
        !          2433:
        !          2434: #ifdef USE_GUI
        !          2435:    /*
        !          2436:     * In GUI there is no point inserting the internal code for a special key.
        !          2437:     * It is more useful to insert the string "<KEY>" instead.  This would
        !          2438:     * probably be useful in a text window too, but it would not be
        !          2439:     * vi-compatible (maybe there should be an option for it?) -- webb
        !          2440:     */
        !          2441:    if (gui.in_use)
        !          2442:        ++allow_keys;
        !          2443: #endif
        !          2444:    ++no_mapping;           /* don't map the next key hits */
        !          2445:    cc = 0;
        !          2446:    for (i = 0; i < 3; ++i)
        !          2447:    {
        !          2448:        do
        !          2449:            nc = vgetc();
        !          2450:        while (nc == K_IGNORE || nc == K_SCROLLBAR || nc == K_HORIZ_SCROLLBAR);
        !          2451:        if (!(State & CMDLINE))
        !          2452:            add_to_showcmd(nc, FALSE);
        !          2453:        if (IS_SPECIAL(nc) || !isdigit(nc))
        !          2454:            break;
        !          2455:        cc = cc * 10 + nc - '0';
        !          2456:        if (cc > 255)
        !          2457:            cc = 255;           /* limit range to 0-255 */
        !          2458:        nc = 0;
        !          2459:    }
        !          2460:    if (i == 0)     /* no number entered */
        !          2461:    {
        !          2462:        if (nc == K_ZERO)   /* NUL is stored as NL */
        !          2463:        {
        !          2464:            cc = '\n';
        !          2465:            nc = 0;
        !          2466:        }
        !          2467:        else
        !          2468:        {
        !          2469:            cc = nc;
        !          2470:            nc = 0;
        !          2471:        }
        !          2472:    }
        !          2473:
        !          2474:    if (cc == 0)        /* NUL is stored as NL */
        !          2475:        cc = '\n';
        !          2476:
        !          2477:    --no_mapping;
        !          2478: #ifdef USE_GUI
        !          2479:    if (gui.in_use)
        !          2480:        --allow_keys;
        !          2481: #endif
        !          2482:    if (nc)
        !          2483:        vungetc(nc);
        !          2484:    got_int = FALSE;        /* CTRL-C typed after CTRL-V is not an interrupt */
        !          2485:    return cc;
        !          2486: }
        !          2487:
        !          2488: /*
        !          2489:  * Insert character, taking care of special keys and mod_mask
        !          2490:  */
        !          2491:    static void
        !          2492: insert_special(c, allow_modmask)
        !          2493:    int     c;
        !          2494:    int     allow_modmask;
        !          2495: {
        !          2496:    char_u  *p;
        !          2497:    int     len;
        !          2498:
        !          2499:    /*
        !          2500:     * Special function key, translate into "<Key>". Up to the last '>' is
        !          2501:     * inserted with ins_str(), so as not to replace characters in replace
        !          2502:     * mode.
        !          2503:     * Only use mod_mask for special keys, to avoid things like <S-Space>,
        !          2504:     * unless 'allow_modmask' is TRUE.
        !          2505:     */
        !          2506:    if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
        !          2507:    {
        !          2508:        p = get_special_key_name(c, mod_mask);
        !          2509:        len = STRLEN(p);
        !          2510:        c = p[len - 1];
        !          2511:        if (len > 2)
        !          2512:        {
        !          2513:            p[len - 1] = NUL;
        !          2514:            ins_str(p);
        !          2515:            AppendToRedobuff(p);
        !          2516:        }
        !          2517:    }
        !          2518:    insertchar(c, FALSE, -1);
        !          2519: }
        !          2520:
        !          2521: /*
        !          2522:  * Special characters in this context are those that need processing other
        !          2523:  * than the simple insertion that can be performed here. This includes ESC
        !          2524:  * which terminates the insert, and CR/NL which need special processing to
        !          2525:  * open up a new line. This routine tries to optimize insertions performed by
        !          2526:  * the "redo", "undo" or "put" commands, so it needs to know when it should
        !          2527:  * stop and defer processing to the "normal" mechanism.
        !          2528:  */
        !          2529: #define ISSPECIAL(c)   ((c) < ' ' || (c) >= DEL)
        !          2530:
        !          2531:    void
        !          2532: insertchar(c, force_formatting, second_indent)
        !          2533:    unsigned    c;
        !          2534:    int         force_formatting;       /* format line regardless of p_fo */
        !          2535:    int         second_indent;          /* indent for second line if >= 0 */
        !          2536: {
        !          2537:    int         haveto_redraw = FALSE;
        !          2538:    int         textwidth;
        !          2539:    colnr_t     leader_len;
        !          2540:    int         first_line = TRUE;
        !          2541:    int         fo_ins_blank;
        !          2542:    int         save_char = NUL;
        !          2543:
        !          2544:    stop_arrow();
        !          2545:
        !          2546:    /*
        !          2547:     * find out textwidth to be used:
        !          2548:     *  if 'textwidth' option is set, use it
        !          2549:     *  else if 'wrapmargin' option is set, use Columns - 'wrapmargin'
        !          2550:     *  if invalid value, use 0.
        !          2551:     *  Set default to window width (maximum 79) for "Q" command.
        !          2552:     */
        !          2553:    textwidth = curbuf->b_p_tw;
        !          2554:    if (textwidth == 0 && curbuf->b_p_wm)
        !          2555:        textwidth = Columns - curbuf->b_p_wm;
        !          2556:    if (textwidth < 0)
        !          2557:        textwidth = 0;
        !          2558:    if (force_formatting && textwidth == 0)
        !          2559:    {
        !          2560:        textwidth = Columns - 1;
        !          2561:        if (textwidth > 79)
        !          2562:            textwidth = 79;
        !          2563:    }
        !          2564:
        !          2565:    fo_ins_blank = has_format_option(FO_INS_BLANK);
        !          2566:
        !          2567:    /*
        !          2568:     * Try to break the line in two or more pieces when:
        !          2569:     * - Always do this if we have been called to do formatting only.
        !          2570:     * - Otherwise:
        !          2571:     *   - Don't do this if inserting a blank
        !          2572:     *   - Don't do this if an existing character is being replaced.
        !          2573:     *   - Do this if the cursor is not on the line where insert started
        !          2574:     *   or - 'formatoptions' doesn't have 'l' or the line was not too long
        !          2575:     *         before the insert.
        !          2576:     *      - 'formatoptions' doesn't have 'b' or a blank was inserted at or
        !          2577:     *        before 'textwidth'
        !          2578:     */
        !          2579:    if (force_formatting || (!vim_iswhite(c) &&
        !          2580:                             !(State == REPLACE && *ml_get_cursor() != NUL) &&
        !          2581:                                    (curwin->w_cursor.lnum != Insstart.lnum ||
        !          2582:                                          ((!has_format_option(FO_INS_LONG) ||
        !          2583:                                    Insstart_textlen <= (colnr_t)textwidth) &&
        !          2584:              (!fo_ins_blank || Insstart_blank_vcol <= (colnr_t)textwidth)))))
        !          2585:    {
        !          2586:        /*
        !          2587:         * When 'ai' is off we don't want a space under the cursor to be
        !          2588:         * deleted.  Replace it with an 'x' temporarily.
        !          2589:         */
        !          2590:        if (!curbuf->b_p_ai && vim_iswhite(gchar_cursor()))
        !          2591:        {
        !          2592:            save_char = gchar_cursor();
        !          2593:            pchar_cursor('x');
        !          2594:        }
        !          2595:        while (textwidth && curwin->w_virtcol >= (colnr_t)textwidth)
        !          2596:        {
        !          2597:            int     startcol;           /* Cursor column at entry */
        !          2598:            int     wantcol;            /* column at textwidth border */
        !          2599:            int     foundcol;           /* column for start of spaces */
        !          2600:            int     end_foundcol = 0;   /* column for start of word */
        !          2601:            colnr_t len;
        !          2602:
        !          2603:            if (!force_formatting && has_format_option(FO_WRAP_COMS))
        !          2604:                fo_do_comments = TRUE;
        !          2605:
        !          2606:            /* Don't break until after the comment leader */
        !          2607:            leader_len = get_leader_len(ml_get_curline(), NULL);
        !          2608:            if (!force_formatting && leader_len == 0 &&
        !          2609:                                                  !has_format_option(FO_WRAP))
        !          2610:
        !          2611:            {
        !          2612:                textwidth = 0;
        !          2613:                break;
        !          2614:            }
        !          2615:            if ((startcol = curwin->w_cursor.col) == 0)
        !          2616:                break;
        !          2617:                                        /* find column of textwidth border */
        !          2618:            coladvance((colnr_t)textwidth);
        !          2619:            wantcol = curwin->w_cursor.col;
        !          2620:
        !          2621:            curwin->w_cursor.col = startcol - 1;
        !          2622:            foundcol = 0;
        !          2623:            /*
        !          2624:             * Find position to break at.
        !          2625:             * Stop at start of line.
        !          2626:             * Stop at first entered white when 'formatoptions' has 'v'
        !          2627:             */
        !          2628:            while (curwin->w_cursor.col > 0 &&
        !          2629:                          ((!fo_ins_blank && !has_format_option(FO_INS_VI)) ||
        !          2630:                                 curwin->w_cursor.lnum != Insstart.lnum ||
        !          2631:                                     curwin->w_cursor.col >= Insstart.col))
        !          2632:            {
        !          2633:                if (vim_iswhite(gchar_cursor()))
        !          2634:                {
        !          2635:                        /* remember position of blank just before text */
        !          2636:                    end_foundcol = curwin->w_cursor.col;
        !          2637:                    while (curwin->w_cursor.col > 0 &&
        !          2638:                                                  vim_iswhite(gchar_cursor()))
        !          2639:                        --curwin->w_cursor.col;
        !          2640:                    if (curwin->w_cursor.col == 0 &&
        !          2641:                                                  vim_iswhite(gchar_cursor()))
        !          2642:                        break;          /* only spaces in front of text */
        !          2643:                    /* Don't break until after the comment leader */
        !          2644:                    if (curwin->w_cursor.col < leader_len)
        !          2645:                        break;
        !          2646:                    foundcol = curwin->w_cursor.col + 1;
        !          2647:                    if (curwin->w_cursor.col < (colnr_t)wantcol)
        !          2648:                        break;
        !          2649:                }
        !          2650:                --curwin->w_cursor.col;
        !          2651:            }
        !          2652:
        !          2653:            if (foundcol == 0)          /* no spaces, cannot break line */
        !          2654:            {
        !          2655:                curwin->w_cursor.col = startcol;
        !          2656:                break;
        !          2657:            }
        !          2658:
        !          2659:            /*
        !          2660:             * offset between cursor position and line break is used by
        !          2661:             * replace stack functions
        !          2662:             */
        !          2663:            replace_offset = startcol - end_foundcol - 1;
        !          2664:
        !          2665:            /*
        !          2666:             * adjust startcol for spaces that will be deleted and
        !          2667:             * characters that will remain on top line
        !          2668:             */
        !          2669:            curwin->w_cursor.col = foundcol;
        !          2670:            while (vim_iswhite(gchar_cursor()))
        !          2671:            {
        !          2672:                ++curwin->w_cursor.col;
        !          2673:                --startcol;
        !          2674:            }
        !          2675:            startcol -= foundcol;
        !          2676:            if (startcol < 0)
        !          2677:                startcol = 0;
        !          2678:
        !          2679:                /* put cursor after pos. to break line */
        !          2680:            curwin->w_cursor.col = foundcol;
        !          2681:
        !          2682:            Opencmd(FORWARD, FALSE, TRUE);
        !          2683:
        !          2684:            replace_offset = 0;
        !          2685:            if (second_indent >= 0 && first_line)
        !          2686:                set_indent(second_indent, TRUE);
        !          2687:            first_line = FALSE;
        !          2688:
        !          2689:            /*
        !          2690:             * check if cursor is not past the NUL off the line, cindent may
        !          2691:             * have added or removed indent.
        !          2692:             */
        !          2693:            curwin->w_cursor.col += startcol;
        !          2694:            len = STRLEN(ml_get_curline());
        !          2695:            if (curwin->w_cursor.col > len)
        !          2696:                curwin->w_cursor.col = len;
        !          2697:
        !          2698:            curs_columns(FALSE);        /* update curwin->w_virtcol */
        !          2699:            haveto_redraw = TRUE;
        !          2700: #ifdef CINDENT
        !          2701:            can_cindent = TRUE;
        !          2702: #endif
        !          2703:        }
        !          2704:
        !          2705:        if (save_char)                  /* put back space after cursor */
        !          2706:            pchar_cursor(save_char);
        !          2707:
        !          2708:        if (c == NUL)                   /* formatting only */
        !          2709:            return;
        !          2710:        fo_do_comments = FALSE;
        !          2711:        if (haveto_redraw)
        !          2712:        {
        !          2713:            /*
        !          2714:             * If the cursor ended up just below the screen we scroll up here
        !          2715:             * to avoid a redraw of the whole screen in the most common cases.
        !          2716:             */
        !          2717:            if (curwin->w_cursor.lnum == curwin->w_botline &&
        !          2718:                                                        !curwin->w_empty_rows)
        !          2719:                win_del_lines(curwin, 0, 1, TRUE, TRUE);
        !          2720:            updateScreen(CURSUPD);
        !          2721:        }
        !          2722:    }
        !          2723:    if (c == NUL)           /* only formatting was wanted */
        !          2724:        return;
        !          2725:
        !          2726:    did_ai = FALSE;
        !          2727:    did_si = FALSE;
        !          2728:    can_si = FALSE;
        !          2729:    can_si_back = FALSE;
        !          2730:
        !          2731:    /*
        !          2732:     * If there's any pending input, grab up to INPUT_BUFLEN at once.
        !          2733:     * This speeds up normal text input considerably.
        !          2734:     */
        !          2735: #define INPUT_BUFLEN 100
        !          2736:    if (!ISSPECIAL(c) && vpeekc() != NUL && State != REPLACE
        !          2737: #ifdef RIGHTLEFT
        !          2738:                                                                && !p_ri
        !          2739: #endif
        !          2740:                                                                        )
        !          2741:    {
        !          2742:        char_u          p[INPUT_BUFLEN + 1];
        !          2743:        int             i;
        !          2744:
        !          2745:        p[0] = c;
        !          2746:        i = 1;
        !          2747:        while ((c = vpeekc()) != NUL && !ISSPECIAL(c) && i < INPUT_BUFLEN &&
        !          2748:                                                            (textwidth == 0 ||
        !          2749:            (curwin->w_virtcol += charsize(p[i - 1])) < (colnr_t)textwidth) &&
        !          2750:                    !(!no_abbr && !iswordchar(c) && iswordchar(p[i - 1])))
        !          2751:        {
        !          2752: #ifdef RIGHTLEFT
        !          2753:            c = vgetc();
        !          2754:            if (p_hkmap && KeyTyped)
        !          2755:                c = hkmap(c);               /* Hebrew mode mapping */
        !          2756:            p[i++] = c;
        !          2757: #else
        !          2758:            p[i++] = vgetc();
        !          2759: #endif
        !          2760:        }
        !          2761:
        !          2762: #ifdef DIGRAPHS
        !          2763:        do_digraph(-1);                 /* clear digraphs */
        !          2764:        do_digraph(p[i-1]);             /* may be the start of a digraph */
        !          2765: #endif
        !          2766:        p[i] = '\0';
        !          2767:        ins_str(p);
        !          2768:        AppendToRedobuff(p);
        !          2769:    }
        !          2770:    else
        !          2771:    {
        !          2772:        ins_char(c);
        !          2773:        AppendCharToRedobuff(c);
        !          2774:    }
        !          2775: }
        !          2776:
        !          2777: /*
        !          2778:  * start_arrow() is called when an arrow key is used in insert mode.
        !          2779:  * It resembles hitting the <ESC> key.
        !          2780:  */
        !          2781:    static void
        !          2782: start_arrow(end_insert_pos)
        !          2783:    FPOS    *end_insert_pos;
        !          2784: {
        !          2785:    if (!arrow_used)        /* something has been inserted */
        !          2786:    {
        !          2787:        AppendToRedobuff(ESC_STR);
        !          2788:        arrow_used = TRUE;      /* this means we stopped the current insert */
        !          2789:        stop_insert(end_insert_pos);
        !          2790:    }
        !          2791: }
        !          2792:
        !          2793: /*
        !          2794:  * stop_arrow() is called before a change is made in insert mode.
        !          2795:  * If an arrow key has been used, start a new insertion.
        !          2796:  */
        !          2797:    static void
        !          2798: stop_arrow()
        !          2799: {
        !          2800:    if (arrow_used)
        !          2801:    {
        !          2802:        (void)u_save_cursor();              /* errors are ignored! */
        !          2803:        Insstart = curwin->w_cursor;    /* new insertion starts here */
        !          2804:        Insstart_textlen = linetabsize(ml_get_curline());
        !          2805:        ResetRedobuff();
        !          2806:        AppendToRedobuff((char_u *)"1i");   /* pretend we start an insertion */
        !          2807:        arrow_used = FALSE;
        !          2808:    }
        !          2809: }
        !          2810:
        !          2811: /*
        !          2812:  * do a few things to stop inserting
        !          2813:  */
        !          2814:    static void
        !          2815: stop_insert(end_insert_pos)
        !          2816:    FPOS    *end_insert_pos;        /* where insert ended */
        !          2817: {
        !          2818:    stop_redo_ins();
        !          2819:
        !          2820:    /*
        !          2821:     * save the inserted text for later redo with ^@
        !          2822:     */
        !          2823:    vim_free(last_insert);
        !          2824:    last_insert = get_inserted();
        !          2825:    last_insert_skip = new_insert_skip;
        !          2826:
        !          2827:    /*
        !          2828:     * If we just did an auto-indent, remove the white space from the end of
        !          2829:     * the line, and put the cursor back.
        !          2830:     */
        !          2831:    if (did_ai && !arrow_used)
        !          2832:    {
        !          2833:        if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
        !          2834:            --curwin->w_cursor.col;
        !          2835:        while (vim_iswhite(gchar_cursor()))
        !          2836:            delchar(TRUE);
        !          2837:        if (gchar_cursor() != NUL)
        !          2838:            ++curwin->w_cursor.col;     /* put cursor back on the NUL */
        !          2839:        if (curwin->w_p_list)           /* the deletion is only seen in list
        !          2840:                                         * mode */
        !          2841:            updateline();
        !          2842:    }
        !          2843:    did_ai = FALSE;
        !          2844:    did_si = FALSE;
        !          2845:    can_si = FALSE;
        !          2846:    can_si_back = FALSE;
        !          2847:
        !          2848:    /* set '[ and '] to the inserted text */
        !          2849:    curbuf->b_op_start = Insstart;
        !          2850:    curbuf->b_op_end = *end_insert_pos;
        !          2851: }
        !          2852:
        !          2853: /*
        !          2854:  * Set the last inserted text to a single character.
        !          2855:  * Used for the replace command.
        !          2856:  */
        !          2857:    void
        !          2858: set_last_insert(c)
        !          2859:    int     c;
        !          2860: {
        !          2861:    vim_free(last_insert);
        !          2862:    last_insert = alloc(4);
        !          2863:    if (last_insert != NULL)
        !          2864:    {
        !          2865:        last_insert[0] = Ctrl('V');
        !          2866:        last_insert[1] = c;
        !          2867:        last_insert[2] = ESC;
        !          2868:        last_insert[3] = NUL;
        !          2869:            /* Use the CTRL-V only when not entering a digit */
        !          2870:        last_insert_skip = isdigit(c) ? 1 : 0;
        !          2871:    }
        !          2872: }
        !          2873:
        !          2874: /*
        !          2875:  * move cursor to start of line
        !          2876:  * if flag == TRUE move to first non-white
        !          2877:  * if flag == MAYBE then move to first non-white if startofline is set,
        !          2878:  *     otherwise don't move at all.
        !          2879:  */
        !          2880:    void
        !          2881: beginline(flag)
        !          2882:    int         flag;
        !          2883: {
        !          2884:    if (flag == MAYBE && !p_sol)
        !          2885:        coladvance(curwin->w_curswant);
        !          2886:    else
        !          2887:    {
        !          2888:        curwin->w_cursor.col = 0;
        !          2889:        if (flag)
        !          2890:        {
        !          2891:            register char_u *ptr;
        !          2892:
        !          2893:            for (ptr = ml_get_curline(); vim_iswhite(*ptr); ++ptr)
        !          2894:                ++curwin->w_cursor.col;
        !          2895:        }
        !          2896:        curwin->w_set_curswant = TRUE;
        !          2897:    }
        !          2898: }
        !          2899:
        !          2900: /*
        !          2901:  * oneright oneleft cursor_down cursor_up
        !          2902:  *
        !          2903:  * Move one char {right,left,down,up}.
        !          2904:  * Return OK when sucessful, FAIL when we hit a line of file boundary.
        !          2905:  */
        !          2906:
        !          2907:    int
        !          2908: oneright()
        !          2909: {
        !          2910:    char_u *ptr;
        !          2911:
        !          2912:    ptr = ml_get_cursor();
        !          2913:    if (*ptr++ == NUL || *ptr == NUL)
        !          2914:        return FAIL;
        !          2915:    curwin->w_set_curswant = TRUE;
        !          2916:    ++curwin->w_cursor.col;
        !          2917:    return OK;
        !          2918: }
        !          2919:
        !          2920:    int
        !          2921: oneleft()
        !          2922: {
        !          2923:    if (curwin->w_cursor.col == 0)
        !          2924:        return FAIL;
        !          2925:    curwin->w_set_curswant = TRUE;
        !          2926:    --curwin->w_cursor.col;
        !          2927:    return OK;
        !          2928: }
        !          2929:
        !          2930:    int
        !          2931: cursor_up(n)
        !          2932:    long n;
        !          2933: {
        !          2934:    if (n != 0 && curwin->w_cursor.lnum == 1)
        !          2935:        return FAIL;
        !          2936:    if (n >= curwin->w_cursor.lnum)
        !          2937:        curwin->w_cursor.lnum = 1;
        !          2938:    else
        !          2939:        curwin->w_cursor.lnum -= n;
        !          2940:
        !          2941:    /* try to advance to the column we want to be at */
        !          2942:    coladvance(curwin->w_curswant);
        !          2943:
        !          2944:    if (op_type == NOP)
        !          2945:        cursupdate();               /* make sure curwin->w_topline is valid */
        !          2946:
        !          2947:    return OK;
        !          2948: }
        !          2949:
        !          2950:    int
        !          2951: cursor_down(n)
        !          2952:    long n;
        !          2953: {
        !          2954:    if (n != 0 && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
        !          2955:        return FAIL;
        !          2956:    curwin->w_cursor.lnum += n;
        !          2957:    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
        !          2958:        curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          2959:
        !          2960:    /* try to advance to the column we want to be at */
        !          2961:    coladvance(curwin->w_curswant);
        !          2962:
        !          2963:    if (op_type == NOP)
        !          2964:        cursupdate();               /* make sure curwin->w_topline is valid */
        !          2965:
        !          2966:    return OK;
        !          2967: }
        !          2968:
        !          2969: /*
        !          2970:  * screengo() --
        !          2971:  *
        !          2972:  * move 'dist' lines in direction 'dir', counting lines by *screen*
        !          2973:  * lines rather than lines in the file
        !          2974:  * 'dist' must be positive.
        !          2975:  *
        !          2976:  * return OK if able to move cursor, FAIL otherwise.
        !          2977:  */
        !          2978:
        !          2979:    int
        !          2980: screengo(dir, dist)
        !          2981:    int     dir;
        !          2982:    long    dist;
        !          2983: {
        !          2984:    int     linelen = linetabsize(ml_get_curline());
        !          2985:    int     retval = OK;
        !          2986:    int     atend = FALSE;
        !          2987:    int     n;
        !          2988:
        !          2989:    op_motion_type = MCHAR;
        !          2990:    op_inclusive = FALSE;
        !          2991:
        !          2992:    /*
        !          2993:     * Instead of sticking at the last character of the line in the file we
        !          2994:     * try to stick in the last column of the screen
        !          2995:     */
        !          2996:    if (curwin->w_curswant == MAXCOL)
        !          2997:    {
        !          2998:        atend = TRUE;
        !          2999:        curwin->w_curswant = ((curwin->w_virtcol +
        !          3000:                       (curwin->w_p_nu ? 8 : 0)) / Columns + 1) * Columns - 1;
        !          3001:        if (curwin->w_p_nu && curwin->w_curswant > 8)
        !          3002:            curwin->w_curswant -= 8;
        !          3003:    }
        !          3004:    else
        !          3005:        while (curwin->w_curswant >= (colnr_t)(linelen + Columns))
        !          3006:            curwin->w_curswant -= Columns;
        !          3007:
        !          3008:    while (dist--)
        !          3009:    {
        !          3010:        if (dir == BACKWARD)
        !          3011:        {
        !          3012:                                                /* move back within line */
        !          3013:            if ((long)curwin->w_curswant >= Columns)
        !          3014:                curwin->w_curswant -= Columns;
        !          3015:            else                                /* to previous line */
        !          3016:            {
        !          3017:                if (curwin->w_cursor.lnum == 1)
        !          3018:                {
        !          3019:                    retval = FAIL;
        !          3020:                    break;
        !          3021:                }
        !          3022:                --curwin->w_cursor.lnum;
        !          3023:                linelen = linetabsize(ml_get_curline());
        !          3024:                n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns)
        !          3025:                                                                    * Columns;
        !          3026:                if (curwin->w_p_nu &&
        !          3027:                                 (long)curwin->w_curswant >= Columns - 8 && n)
        !          3028:                    n -= Columns;
        !          3029:                curwin->w_curswant += n;
        !          3030:            }
        !          3031:        }
        !          3032:        else /* dir == FORWARD */
        !          3033:        {
        !          3034:            n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns) * Columns;
        !          3035:            if (curwin->w_p_nu && n > 8)
        !          3036:                n -= 8;
        !          3037:                                                /* move forward within line */
        !          3038:            if (curwin->w_curswant < (colnr_t)n)
        !          3039:                curwin->w_curswant += Columns;
        !          3040:            else                                /* to next line */
        !          3041:            {
        !          3042:                if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
        !          3043:                {
        !          3044:                    retval = FAIL;
        !          3045:                    break;
        !          3046:                }
        !          3047:                curwin->w_cursor.lnum++;
        !          3048:                linelen = linetabsize(ml_get_curline());
        !          3049:                curwin->w_curswant %= Columns;
        !          3050:            }
        !          3051:        }
        !          3052:    }
        !          3053:    coladvance(curwin->w_curswant);
        !          3054:    if (atend)
        !          3055:        curwin->w_curswant = MAXCOL;        /* stick in the last column */
        !          3056:    if (op_type == NOP)
        !          3057:        cursupdate();
        !          3058:    return retval;
        !          3059: }
        !          3060:
        !          3061: /*
        !          3062:  * move screen 'count' pages up or down and update screen
        !          3063:  *
        !          3064:  * return FAIL for failure, OK otherwise
        !          3065:  */
        !          3066:    int
        !          3067: onepage(dir, count)
        !          3068:    int     dir;
        !          3069:    long    count;
        !          3070: {
        !          3071:    linenr_t        lp;
        !          3072:    long            n;
        !          3073:    int             off;
        !          3074:
        !          3075:    if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
        !          3076:        return FAIL;
        !          3077:    for ( ; count > 0; --count)
        !          3078:    {
        !          3079:        if (dir == FORWARD ? (curwin->w_topline >=
        !          3080:                   curbuf->b_ml.ml_line_count - 1) : (curwin->w_topline == 1))
        !          3081:        {
        !          3082:            beep_flush();
        !          3083:            return FAIL;
        !          3084:        }
        !          3085:        if (dir == FORWARD)
        !          3086:        {
        !          3087:                                        /* at end of file */
        !          3088:            if (curwin->w_botline > curbuf->b_ml.ml_line_count)
        !          3089:                curwin->w_topline = curbuf->b_ml.ml_line_count;
        !          3090:                                        /* next line is big */
        !          3091:                                        /* or just three lines on screen */
        !          3092:            else
        !          3093:            {
        !          3094:                if (plines(curwin->w_botline) >= curwin->w_height - 2 ||
        !          3095:                                   curwin->w_botline - curwin->w_topline <= 3)
        !          3096:                    off = 0;
        !          3097:                else
        !          3098:                    off = 2;
        !          3099:                curwin->w_topline = curwin->w_botline - off;
        !          3100:                curwin->w_cursor.lnum = curwin->w_topline;
        !          3101:            }
        !          3102:            comp_Botline(curwin);
        !          3103:        }
        !          3104:        else    /* dir == BACKWARDS */
        !          3105:        {
        !          3106:            lp = curwin->w_topline;
        !          3107:            /*
        !          3108:             * If the first two lines on the screen are not too big, we keep
        !          3109:             * them on the screen.
        !          3110:             */
        !          3111:            if ((n = plines(lp)) > curwin->w_height / 2)
        !          3112:                --lp;
        !          3113:            else if (lp < curbuf->b_ml.ml_line_count &&
        !          3114:                                    n + plines(lp + 1) < curwin->w_height / 2)
        !          3115:                ++lp;
        !          3116:            curwin->w_cursor.lnum = lp;
        !          3117:            n = 0;
        !          3118:            while (n <= curwin->w_height && lp >= 1)
        !          3119:            {
        !          3120:                n += plines(lp);
        !          3121:                --lp;
        !          3122:            }
        !          3123:            if (n <= curwin->w_height)              /* at begin of file */
        !          3124:            {
        !          3125:                curwin->w_topline = 1;
        !          3126:                comp_Botline(curwin);
        !          3127:            }
        !          3128:            else if (lp >= curwin->w_topline - 2)   /* very long lines */
        !          3129:            {
        !          3130:                --curwin->w_topline;
        !          3131:                comp_Botline(curwin);
        !          3132:                curwin->w_cursor.lnum = curwin->w_botline - 1;
        !          3133:            }
        !          3134:            else
        !          3135:            {
        !          3136:                curwin->w_topline = lp + 2;
        !          3137:                comp_Botline(curwin);
        !          3138:            }
        !          3139:        }
        !          3140:    }
        !          3141:    cursor_correct();
        !          3142:    beginline(MAYBE);
        !          3143:    updateScreen(VALID);
        !          3144:    return OK;
        !          3145: }
        !          3146:
        !          3147: /* #define KEEP_SCREEN_LINE */
        !          3148:
        !          3149:    void
        !          3150: halfpage(flag, Prenum)
        !          3151:    int         flag;
        !          3152:    linenr_t    Prenum;
        !          3153: {
        !          3154:    long        scrolled = 0;
        !          3155:    int         i;
        !          3156:    int         n;
        !          3157:
        !          3158:    if (Prenum)
        !          3159:        curwin->w_p_scroll = (Prenum > curwin->w_height) ?
        !          3160:                                                curwin->w_height : Prenum;
        !          3161:    n = (curwin->w_p_scroll <= curwin->w_height) ?
        !          3162:                                    curwin->w_p_scroll : curwin->w_height;
        !          3163:
        !          3164:    if (flag)       /* scroll down */
        !          3165:    {
        !          3166:        while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
        !          3167:        {
        !          3168:            i = plines(curwin->w_topline);
        !          3169:            n -= i;
        !          3170:            if (n < 0 && scrolled)
        !          3171:                break;
        !          3172:            scrolled += i;
        !          3173:            ++curwin->w_topline;
        !          3174:            comp_Botline(curwin);       /* compute curwin->w_botline */
        !          3175: #ifndef KEEP_SCREEN_LINE
        !          3176:            if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
        !          3177:                ++curwin->w_cursor.lnum;
        !          3178: #endif
        !          3179:        }
        !          3180: #ifndef KEEP_SCREEN_LINE
        !          3181:        /*
        !          3182:         * When hit bottom of the file: move cursor down.
        !          3183:         */
        !          3184:        if (n > 0)
        !          3185:        {
        !          3186:            curwin->w_cursor.lnum += n;
        !          3187:            if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
        !          3188:                curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          3189:        }
        !          3190: #else
        !          3191:            /* try to put the cursor in the same screen line */
        !          3192:        while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
        !          3193:                             && curwin->w_cursor.lnum < curwin->w_botline - 1)
        !          3194:        {
        !          3195:            scrolled -= plines(curwin->w_cursor.lnum);
        !          3196:            if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
        !          3197:                break;
        !          3198:            ++curwin->w_cursor.lnum;
        !          3199:        }
        !          3200: #endif
        !          3201:    }
        !          3202:    else            /* scroll up */
        !          3203:    {
        !          3204:        while (n > 0 && curwin->w_topline > 1)
        !          3205:        {
        !          3206:            i = plines(curwin->w_topline - 1);
        !          3207:            n -= i;
        !          3208:            if (n < 0 && scrolled)
        !          3209:                break;
        !          3210:            scrolled += i;
        !          3211:            --curwin->w_topline;
        !          3212: #ifndef KEEP_SCREEN_LINE
        !          3213:            if (curwin->w_cursor.lnum > 1)
        !          3214:                --curwin->w_cursor.lnum;
        !          3215: #endif
        !          3216:        }
        !          3217:        comp_Botline(curwin);       /* compute curwin->w_botline */
        !          3218: #ifndef KEEP_SCREEN_LINE
        !          3219:        /*
        !          3220:         * When hit top of the file: move cursor up.
        !          3221:         */
        !          3222:        if (n > 0)
        !          3223:        {
        !          3224:            if (curwin->w_cursor.lnum > (linenr_t)n)
        !          3225:                curwin->w_cursor.lnum -= n;
        !          3226:            else
        !          3227:                curwin->w_cursor.lnum = 1;
        !          3228:        }
        !          3229: #else
        !          3230:            /* try to put the cursor in the same screen line */
        !          3231:        scrolled += n;      /* move cursor when topline is 1 */
        !          3232:        while (curwin->w_cursor.lnum > curwin->w_topline &&
        !          3233:                 (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
        !          3234:        {
        !          3235:            scrolled -= plines(curwin->w_cursor.lnum - 1);
        !          3236:            if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
        !          3237:                break;
        !          3238:            --curwin->w_cursor.lnum;
        !          3239:        }
        !          3240: #endif
        !          3241:    }
        !          3242:    cursor_correct();
        !          3243:    beginline(MAYBE);
        !          3244:    updateScreen(VALID);
        !          3245: }
        !          3246:
        !          3247: /*
        !          3248:  * Stuff the last inserted text in the read buffer.
        !          3249:  * Last_insert actually is a copy of the redo buffer, so we
        !          3250:  * first have to remove the command.
        !          3251:  */
        !          3252:    int
        !          3253: stuff_inserted(c, count, no_esc)
        !          3254:    int     c;
        !          3255:    long    count;
        !          3256:    int     no_esc;
        !          3257: {
        !          3258:    char_u      *esc_ptr = NULL;
        !          3259:    char_u      *ptr;
        !          3260:
        !          3261:    ptr = get_last_insert();
        !          3262:    if (ptr == NULL)
        !          3263:    {
        !          3264:        EMSG(e_noinstext);
        !          3265:        return FAIL;
        !          3266:    }
        !          3267:
        !          3268:    if (c)
        !          3269:        stuffcharReadbuff(c);
        !          3270:    if (no_esc && (esc_ptr = (char_u *)vim_strrchr(ptr, 27)) != NULL)
        !          3271:        *esc_ptr = NUL;     /* remove the ESC */
        !          3272:
        !          3273:    do
        !          3274:        stuffReadbuff(ptr);
        !          3275:    while (--count > 0);
        !          3276:
        !          3277:    if (esc_ptr != NULL)
        !          3278:        *esc_ptr = 27;      /* put the ESC back */
        !          3279:
        !          3280:    return OK;
        !          3281: }
        !          3282:
        !          3283:    char_u *
        !          3284: get_last_insert()
        !          3285: {
        !          3286:    if (last_insert == NULL)
        !          3287:        return NULL;
        !          3288:    return last_insert + last_insert_skip;
        !          3289: }
        !          3290:
        !          3291: /*
        !          3292:  * Check the word in front of the cursor for an abbreviation.
        !          3293:  * Called when the non-id character "c" has been entered.
        !          3294:  * When an abbreviation is recognized it is removed from the text and
        !          3295:  * the replacement string is inserted in typebuf[], followed by "c".
        !          3296:  */
        !          3297:    static int
        !          3298: echeck_abbr(c)
        !          3299:    int c;
        !          3300: {
        !          3301:    if (p_paste || no_abbr)         /* no abbreviations or in paste mode */
        !          3302:        return FALSE;
        !          3303:
        !          3304:    return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
        !          3305:                curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
        !          3306: }
        !          3307:
        !          3308: /*
        !          3309:  * replace-stack functions
        !          3310:  *
        !          3311:  * When replacing characters the replaced character is remembered
        !          3312:  * for each new character. This is used to re-insert the old text
        !          3313:  * when backspacing.
        !          3314:  *
        !          3315:  * replace_offset is normally 0, in which case replace_push will add a new
        !          3316:  * character at the end of the stack. If replace_offset is not 0, that many
        !          3317:  * characters will be left on the stack above the newly inserted character.
        !          3318:  */
        !          3319:
        !          3320: char_u *replace_stack = NULL;
        !          3321: long   replace_stack_nr = 0;       /* next entry in replace stack */
        !          3322: long   replace_stack_len = 0;      /* max. number of entries */
        !          3323:
        !          3324:    void
        !          3325: replace_push(c)
        !          3326:    int     c;      /* character that is replaced (NUL is none) */
        !          3327: {
        !          3328:    char_u  *p;
        !          3329:
        !          3330:    if (replace_stack_nr < replace_offset)      /* nothing to do */
        !          3331:        return;
        !          3332:    if (replace_stack_len <= replace_stack_nr)
        !          3333:    {
        !          3334:        replace_stack_len += 50;
        !          3335:        p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
        !          3336:        if (p == NULL)      /* out of memory */
        !          3337:        {
        !          3338:            replace_stack_len -= 50;
        !          3339:            return;
        !          3340:        }
        !          3341:        if (replace_stack != NULL)
        !          3342:        {
        !          3343:            vim_memmove(p, replace_stack,
        !          3344:                                 (size_t)(replace_stack_nr * sizeof(char_u)));
        !          3345:            vim_free(replace_stack);
        !          3346:        }
        !          3347:        replace_stack = p;
        !          3348:    }
        !          3349:    p = replace_stack + replace_stack_nr - replace_offset;
        !          3350:    if (replace_offset)
        !          3351:        vim_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
        !          3352:    *p = c;
        !          3353:    ++replace_stack_nr;
        !          3354: }
        !          3355:
        !          3356: /*
        !          3357:  * pop one item from the replace stack
        !          3358:  * return -1 if stack empty
        !          3359:  * return 0 if no character was replaced
        !          3360:  * return replaced character otherwise
        !          3361:  */
        !          3362:    int
        !          3363: replace_pop()
        !          3364: {
        !          3365:    if (replace_stack_nr == 0)
        !          3366:        return -1;
        !          3367:    return (int)replace_stack[--replace_stack_nr];
        !          3368: }
        !          3369:
        !          3370: /*
        !          3371:  * make the replace stack empty
        !          3372:  * (called when exiting replace mode)
        !          3373:  */
        !          3374:    void
        !          3375: replace_flush()
        !          3376: {
        !          3377:    vim_free(replace_stack);
        !          3378:    replace_stack = NULL;
        !          3379:    replace_stack_len = 0;
        !          3380:    replace_stack_nr = 0;
        !          3381: }
        !          3382:
        !          3383: #if defined(LISPINDENT) || defined(CINDENT)
        !          3384: /*
        !          3385:  * Re-indent the current line, based on the current contents of it and the
        !          3386:  * surrounding lines. Fixing the cursor position seems really easy -- I'm very
        !          3387:  * confused what all the part that handles Control-T is doing that I'm not.
        !          3388:  * "get_the_indent" should be get_c_indent or get_lisp_indent.
        !          3389:  */
        !          3390:
        !          3391:    void
        !          3392: fixthisline(get_the_indent)
        !          3393:    int (*get_the_indent) __ARGS((void));
        !          3394: {
        !          3395:    change_indent(INDENT_SET, get_the_indent(), FALSE);
        !          3396:    if (linewhite(curwin->w_cursor.lnum))
        !          3397:        did_ai = TRUE;      /* delete the indent if the line stays empty */
        !          3398: }
        !          3399: #endif /* defined(LISPINDENT) || defined(CINDENT) */
        !          3400:
        !          3401: #ifdef CINDENT
        !          3402: /*
        !          3403:  * return TRUE if 'cinkeys' contains the key "keytyped",
        !          3404:  * when == '*':        Only if key is preceded with '*'    (indent before insert)
        !          3405:  * when == '!':        Only if key is prededed with '!'    (don't insert)
        !          3406:  * when == ' ':        Only if key is not preceded with '*'(indent afterwards)
        !          3407:  *
        !          3408:  * If line_is_empty is TRUE accept keys with '0' before them.
        !          3409:  */
        !          3410:    int
        !          3411: in_cinkeys(keytyped, when, line_is_empty)
        !          3412:    int         keytyped;
        !          3413:    int         when;
        !          3414:    int         line_is_empty;
        !          3415: {
        !          3416:    char_u  *look;
        !          3417:    int     try_match;
        !          3418:    char_u  *p;
        !          3419:
        !          3420:    for (look = curbuf->b_p_cink; *look; )
        !          3421:    {
        !          3422:        /*
        !          3423:         * Find out if we want to try a match with this key, depending on
        !          3424:         * 'when' and a '*' or '!' before the key.
        !          3425:         */
        !          3426:        switch (when)
        !          3427:        {
        !          3428:            case '*': try_match = (*look == '*'); break;
        !          3429:            case '!': try_match = (*look == '!'); break;
        !          3430:             default: try_match = (*look != '*'); break;
        !          3431:        }
        !          3432:        if (*look == '*' || *look == '!')
        !          3433:            ++look;
        !          3434:
        !          3435:        /*
        !          3436:         * If there is a '0', only accept a match if the line is empty.
        !          3437:         */
        !          3438:        if (*look == '0')
        !          3439:        {
        !          3440:            if (!line_is_empty)
        !          3441:                try_match = FALSE;
        !          3442:            ++look;
        !          3443:        }
        !          3444:
        !          3445:        /*
        !          3446:         * does it look like a control character?
        !          3447:         */
        !          3448:        if (*look == '^' && look[1] >= '@' && look[1] <= '_')
        !          3449:        {
        !          3450:            if (try_match && keytyped == Ctrl(look[1]))
        !          3451:                return TRUE;
        !          3452:            look += 2;
        !          3453:        }
        !          3454:        /*
        !          3455:         * 'o' means "o" command, open forward.
        !          3456:         * 'O' means "O" command, open backward.
        !          3457:         */
        !          3458:        else if (*look == 'o')
        !          3459:        {
        !          3460:            if (try_match && keytyped == KEY_OPEN_FORW)
        !          3461:                return TRUE;
        !          3462:            ++look;
        !          3463:        }
        !          3464:        else if (*look == 'O')
        !          3465:        {
        !          3466:            if (try_match && keytyped == KEY_OPEN_BACK)
        !          3467:                return TRUE;
        !          3468:            ++look;
        !          3469:        }
        !          3470:
        !          3471:        /*
        !          3472:         * 'e' means to check for "else" at start of line and just before the
        !          3473:         * cursor.
        !          3474:         */
        !          3475:        else if (*look == 'e')
        !          3476:        {
        !          3477:            if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
        !          3478:            {
        !          3479:                p = ml_get_curline();
        !          3480:                if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
        !          3481:                        STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
        !          3482:                    return TRUE;
        !          3483:            }
        !          3484:            ++look;
        !          3485:        }
        !          3486:
        !          3487:        /*
        !          3488:         * ':' only causes an indent if it is at the end of a label or case
        !          3489:         * statement.
        !          3490:         */
        !          3491:        else if (*look == ':')
        !          3492:        {
        !          3493:            if (try_match && keytyped == ':')
        !          3494:            {
        !          3495:                p = ml_get_curline();
        !          3496:                if (iscase(p) || islabel(30))
        !          3497:                    return TRUE;
        !          3498:            }
        !          3499:            ++look;
        !          3500:        }
        !          3501:
        !          3502:
        !          3503:        /*
        !          3504:         * Is it a key in <>, maybe?
        !          3505:         */
        !          3506:        else if (*look == '<')
        !          3507:        {
        !          3508:            if (try_match)
        !          3509:            {
        !          3510:                /*
        !          3511:                 * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>
        !          3512:                 * and <!> so that people can re-indent on o, O, e, 0, <, >, *
        !          3513:                 * and ! keys if they really really want to.
        !          3514:                 */
        !          3515:                if (vim_strchr((char_u *)"<>!*oOe0", look[1]) != NULL &&
        !          3516:                                                          keytyped == look[1])
        !          3517:                    return TRUE;
        !          3518:
        !          3519:                if (keytyped == get_special_key_code(look + 1))
        !          3520:                    return TRUE;
        !          3521:            }
        !          3522:            while (*look && *look != '>')
        !          3523:                look++;
        !          3524:            while (*look == '>')
        !          3525:                look++;
        !          3526:        }
        !          3527:
        !          3528:        /*
        !          3529:         * ok, it's a boring generic character.
        !          3530:         */
        !          3531:        else
        !          3532:        {
        !          3533:            if (try_match && *look == keytyped)
        !          3534:                return TRUE;
        !          3535:            ++look;
        !          3536:        }
        !          3537:
        !          3538:        /*
        !          3539:         * Skip over ", ".
        !          3540:         */
        !          3541:        look = skip_to_option_part(look);
        !          3542:    }
        !          3543:    return FALSE;
        !          3544: }
        !          3545: #endif /* CINDENT */
        !          3546:
        !          3547: #if defined(RIGHTLEFT) || defined(PROTO)
        !          3548: /*
        !          3549:  * Map Hebrew keyboard when in hkmap mode.
        !          3550:  */
        !          3551:    int
        !          3552: hkmap(c)
        !          3553:    int c;
        !          3554: {
        !          3555:    switch(c)
        !          3556:    {
        !          3557:        case '`':   return ';';
        !          3558:        case '/':   return '.';
        !          3559:        case '\'':  return ',';
        !          3560:        case 'q':   return '/';
        !          3561:        case 'w':   return '\'';
        !          3562:
        !          3563:        /* Hebrew letters - set offset from 'a' */
        !          3564:        case ',':   c = '{'; break;
        !          3565:        case '.':   c = 'v'; break;
        !          3566:        case ';':   c = 't'; break;
        !          3567:        default: {
        !          3568:                    static char str[] = "zqbcxlsjphmkwonu ydafe rig";
        !          3569:
        !          3570:                    if (c < 'a' || c > 'z')
        !          3571:                        return c;
        !          3572:                    c = str[c - 'a'];
        !          3573:                    break;
        !          3574:                }
        !          3575:        }
        !          3576:
        !          3577:    return c - 'a' + p_aleph;
        !          3578: }
        !          3579: #endif