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

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