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

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