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

Annotation of src/usr.bin/vim/screen.c, Revision 1.1

1.1     ! downsj      1: /* $OpenBSD$   */
        !             2: /* vi:set ts=4 sw=4:
        !             3:  *
        !             4:  * VIM - Vi IMproved       by Bram Moolenaar
        !             5:  *
        !             6:  * Do ":help uganda"  in Vim to read copying and usage conditions.
        !             7:  * Do ":help credits" in Vim to see a list of people who contributed.
        !             8:  */
        !             9:
        !            10: /*
        !            11:  * screen.c: code for displaying on the screen
        !            12:  */
        !            13:
        !            14: #include "vim.h"
        !            15: #include "globals.h"
        !            16: #include "proto.h"
        !            17: #include "option.h"
        !            18: #include "ops.h"       /* For op_inclusive */
        !            19:
        !            20: char *tgoto __PARMS((char *cm, int col, int line));
        !            21:
        !            22: static int     canopt;         /* TRUE when cursor goto can be optimized */
        !            23: static int     attributes = 0; /* current attributes for screen character*/
        !            24: static int         highlight_attr = 0; /* attributes when highlighting on */
        !            25: #ifdef RIGHTLEFT
        !            26: static int     rightleft = 0;  /* set to 1 for right to left in screen_fill */
        !            27: #endif
        !            28:
        !            29: static int win_line __ARGS((WIN *, linenr_t, int, int));
        !            30: static void comp_Botline_sub __ARGS((WIN *wp, linenr_t lnum, int done));
        !            31: static void screen_char __ARGS((char_u *, int, int));
        !            32: static void screenclear2 __ARGS((void));
        !            33: static void lineclear __ARGS((char_u *p));
        !            34: static int screen_ins_lines __ARGS((int, int, int, int));
        !            35:
        !            36: /*
        !            37:  * updateline() - like updateScreen() but only for cursor line
        !            38:  *
        !            39:  * Check if the size of the cursor line has changed.  If it did change, lines
        !            40:  * below the cursor will move up or down and we need to call the routine
        !            41:  * updateScreen() to examine the entire screen.
        !            42:  */
        !            43:    void
        !            44: updateline()
        !            45: {
        !            46:    int         row;
        !            47:    int         n;
        !            48:
        !            49:    if (!screen_valid(TRUE))
        !            50:        return;
        !            51:
        !            52:    if (must_redraw)                    /* must redraw whole screen */
        !            53:    {
        !            54:        updateScreen(must_redraw);
        !            55:        return;
        !            56:    }
        !            57:
        !            58:    if (RedrawingDisabled)
        !            59:    {
        !            60:        must_redraw = NOT_VALID;        /* remember to update later */
        !            61:        return;
        !            62:    }
        !            63:
        !            64:    cursor_off();
        !            65:
        !            66:    (void)set_highlight('v');
        !            67:    row = win_line(curwin, curwin->w_cursor.lnum,
        !            68:                                       curwin->w_cline_row, curwin->w_height);
        !            69:
        !            70:    if (row == curwin->w_height + 1)    /* line too long for window */
        !            71:    {
        !            72:            /* window needs to be scrolled up to show the cursor line */
        !            73:        if (curwin->w_topline < curwin->w_cursor.lnum)
        !            74:            ++curwin->w_topline;
        !            75:        updateScreen(VALID_TO_CURSCHAR);
        !            76:        cursupdate();
        !            77:    }
        !            78:    else if (!dollar_vcol)
        !            79:    {
        !            80:        n = row - curwin->w_cline_row;
        !            81:        if (n != curwin->w_cline_height)        /* line changed size */
        !            82:        {
        !            83:            if (n < curwin->w_cline_height)     /* got smaller: delete lines */
        !            84:                win_del_lines(curwin, row,
        !            85:                                     curwin->w_cline_height - n, FALSE, TRUE);
        !            86:            else                                /* got bigger: insert lines */
        !            87:                win_ins_lines(curwin,
        !            88:                                 curwin->w_cline_row + curwin->w_cline_height,
        !            89:                                     n - curwin->w_cline_height, FALSE, TRUE);
        !            90:            updateScreen(VALID_TO_CURSCHAR);
        !            91:        }
        !            92:        else if (clear_cmdline || redraw_cmdline)
        !            93:            showmode();             /* clear cmdline, show mode and ruler */
        !            94:    }
        !            95: }
        !            96:
        !            97: /*
        !            98:  * update all windows that are editing the current buffer
        !            99:  */
        !           100:    void
        !           101: update_curbuf(type)
        !           102:    int         type;
        !           103: {
        !           104:    WIN             *wp;
        !           105:
        !           106:    for (wp = firstwin; wp; wp = wp->w_next)
        !           107:        if (wp->w_buffer == curbuf && wp->w_redr_type < type)
        !           108:            wp->w_redr_type = type;
        !           109:    updateScreen(type);
        !           110: }
        !           111:
        !           112: /*
        !           113:  * updateScreen()
        !           114:  *
        !           115:  * Based on the current value of curwin->w_topline, transfer a screenfull
        !           116:  * of stuff from Filemem to NextScreen, and update curwin->w_botline.
        !           117:  */
        !           118:
        !           119:    void
        !           120: updateScreen(type)
        !           121:    int             type;
        !           122: {
        !           123:    WIN             *wp;
        !           124:
        !           125:    if (!screen_valid(TRUE))
        !           126:        return;
        !           127:
        !           128:    dollar_vcol = 0;
        !           129:
        !           130:    if (must_redraw)
        !           131:    {
        !           132:        if (type < must_redraw)     /* use maximal type */
        !           133:            type = must_redraw;
        !           134:        must_redraw = 0;
        !           135:    }
        !           136:
        !           137:    if (type == CURSUPD)        /* update cursor and then redraw NOT_VALID */
        !           138:    {
        !           139:        curwin->w_lsize_valid = 0;
        !           140:        cursupdate();           /* will call updateScreen() */
        !           141:        return;
        !           142:    }
        !           143:    if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
        !           144:        type = NOT_VALID;
        !           145:
        !           146:    if (RedrawingDisabled)
        !           147:    {
        !           148:        must_redraw = type;     /* remember type for next time */
        !           149:        curwin->w_redr_type = type;
        !           150:        curwin->w_lsize_valid = 0;      /* don't use w_lsize[] now */
        !           151:        return;
        !           152:    }
        !           153:
        !           154:    /*
        !           155:     * if the screen was scrolled up when displaying a message, scroll it down
        !           156:     */
        !           157:    if (msg_scrolled)
        !           158:    {
        !           159:        clear_cmdline = TRUE;
        !           160:        if (msg_scrolled > Rows - 5)        /* clearing is faster */
        !           161:            type = CLEAR;
        !           162:        else if (type != CLEAR)
        !           163:        {
        !           164:            if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
        !           165:                type = CLEAR;
        !           166:            win_rest_invalid(firstwin);     /* should do only first/last few */
        !           167:        }
        !           168:        msg_scrolled = 0;
        !           169:        need_wait_return = FALSE;
        !           170:    }
        !           171:
        !           172:    /*
        !           173:     * reset cmdline_row now (may have been changed temporarily)
        !           174:     */
        !           175:    compute_cmdrow();
        !           176:
        !           177:    if (type == CLEAR)          /* first clear screen */
        !           178:    {
        !           179:        screenclear();          /* will reset clear_cmdline */
        !           180:        type = NOT_VALID;
        !           181:    }
        !           182:
        !           183:    if (clear_cmdline)          /* first clear cmdline */
        !           184:    {
        !           185:        if (emsg_on_display)
        !           186:        {
        !           187:            mch_delay(1000L, TRUE);
        !           188:            emsg_on_display = FALSE;
        !           189:        }
        !           190:        msg_row = cmdline_row;
        !           191:        msg_col = 0;
        !           192:        msg_clr_eos();          /* will reset clear_cmdline */
        !           193:    }
        !           194:
        !           195: /* return if there is nothing to do */
        !           196:    if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0]) ||
        !           197:            (type == INVERTED &&
        !           198:                    curwin->w_old_cursor_lnum == curwin->w_cursor.lnum &&
        !           199:                    curwin->w_old_cursor_vcol == curwin->w_virtcol &&
        !           200:                    curwin->w_old_curswant == curwin->w_curswant)))
        !           201:    {
        !           202:        /*
        !           203:         * go from top to bottom through the windows, redrawing the ones that
        !           204:         * need it
        !           205:         */
        !           206:        curwin->w_redr_type = type;
        !           207:        cursor_off();
        !           208:        for (wp = firstwin; wp; wp = wp->w_next)
        !           209:        {
        !           210:            if (wp->w_redr_type)
        !           211:                win_update(wp);
        !           212:            if (wp->w_redr_status)
        !           213:                win_redr_status(wp);
        !           214:        }
        !           215:    }
        !           216:    if (redraw_cmdline)
        !           217:        showmode();
        !           218: }
        !           219:
        !           220: #ifdef USE_GUI
        !           221: /*
        !           222:  * Update a single window, its status line and maybe the command line msg.
        !           223:  * Used for the GUI scrollbar.
        !           224:  */
        !           225:    void
        !           226: updateWindow(wp)
        !           227:    WIN     *wp;
        !           228: {
        !           229:    win_update(wp);
        !           230:    if (wp->w_redr_status)
        !           231:        win_redr_status(wp);
        !           232:    if (redraw_cmdline)
        !           233:        showmode();
        !           234: }
        !           235: #endif
        !           236:
        !           237: /*
        !           238:  * update a single window
        !           239:  *
        !           240:  * This may cause the windows below it also to be redrawn
        !           241:  */
        !           242:    void
        !           243: win_update(wp)
        !           244:    WIN     *wp;
        !           245: {
        !           246:    int             type = wp->w_redr_type;
        !           247:    register int    row;
        !           248:    register int    endrow;
        !           249:    linenr_t        lnum;
        !           250:    linenr_t        lastline = 0;   /* only valid if endrow != Rows -1 */
        !           251:    int             done;           /* if TRUE, we hit the end of the file */
        !           252:    int             didline;        /* if TRUE, we finished the last line */
        !           253:    int             srow = 0;       /* starting row of the current line */
        !           254:    int             idx;
        !           255:    int             i;
        !           256:    long            j;
        !           257:
        !           258:    if (type == NOT_VALID)
        !           259:    {
        !           260:        wp->w_redr_status = TRUE;
        !           261:        wp->w_lsize_valid = 0;
        !           262:    }
        !           263:
        !           264:    idx = 0;
        !           265:    row = 0;
        !           266:    lnum = wp->w_topline;
        !           267:
        !           268:    /* The number of rows shown is w_height. */
        !           269:    /* The default last row is the status/command line. */
        !           270:    endrow = wp->w_height;
        !           271:
        !           272:    if (type == VALID || type == VALID_TO_CURSCHAR)
        !           273:    {
        !           274:        /*
        !           275:         * We handle two special cases:
        !           276:         * 1: we are off the top of the screen by a few lines: scroll down
        !           277:         * 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
        !           278:         */
        !           279:        if (wp->w_topline < wp->w_lsize_lnum[0])    /* may scroll down */
        !           280:        {
        !           281:            j = wp->w_lsize_lnum[0] - wp->w_topline;
        !           282:            if (j < wp->w_height - 2)               /* not too far off */
        !           283:            {
        !           284:                lastline = wp->w_lsize_lnum[0] - 1;
        !           285:                i = plines_m_win(wp, wp->w_topline, lastline);
        !           286:                if (i < wp->w_height - 2)       /* less than a screen off */
        !           287:                {
        !           288:                    /*
        !           289:                     * Try to insert the correct number of lines.
        !           290:                     * If not the last window, delete the lines at the bottom.
        !           291:                     * win_ins_lines may fail.
        !           292:                     */
        !           293:                    if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK &&
        !           294:                                                    wp->w_lsize_valid)
        !           295:                    {
        !           296:                        endrow = i;
        !           297:
        !           298:                        if ((wp->w_lsize_valid += j) > wp->w_height)
        !           299:                            wp->w_lsize_valid = wp->w_height;
        !           300:                        for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
        !           301:                        {
        !           302:                            wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
        !           303:                            wp->w_lsize[idx] = wp->w_lsize[idx - j];
        !           304:                        }
        !           305:                        idx = 0;
        !           306:                    }
        !           307:                }
        !           308:                else if (lastwin == firstwin)
        !           309:                    screenclear();  /* far off: clearing the screen is faster */
        !           310:            }
        !           311:            else if (lastwin == firstwin)
        !           312:                screenclear();      /* far off: clearing the screen is faster */
        !           313:        }
        !           314:        else                            /* may scroll up */
        !           315:        {
        !           316:            j = -1;
        !           317:                        /* try to find wp->w_topline in wp->w_lsize_lnum[] */
        !           318:            for (i = 0; i < wp->w_lsize_valid; i++)
        !           319:            {
        !           320:                if (wp->w_lsize_lnum[i] == wp->w_topline)
        !           321:                {
        !           322:                    j = i;
        !           323:                    break;
        !           324:                }
        !           325:                row += wp->w_lsize[i];
        !           326:            }
        !           327:            if (j == -1)    /* wp->w_topline is not in wp->w_lsize_lnum */
        !           328:            {
        !           329:                row = 0;
        !           330:                if (lastwin == firstwin)
        !           331:                    screenclear();  /* far off: clearing the screen is faster */
        !           332:            }
        !           333:            else
        !           334:            {
        !           335:                /*
        !           336:                 * Try to delete the correct number of lines.
        !           337:                 * wp->w_topline is at wp->w_lsize_lnum[i].
        !           338:                 */
        !           339:                if ((row == 0 || win_del_lines(wp, 0, row,
        !           340:                            FALSE, wp == firstwin) == OK) && wp->w_lsize_valid)
        !           341:                {
        !           342:                    srow = row;
        !           343:                    row = 0;
        !           344:                    for (;;)
        !           345:                    {
        !           346:                        if (type == VALID_TO_CURSCHAR &&
        !           347:                                                    lnum == wp->w_cursor.lnum)
        !           348:                                break;
        !           349:                        if (row + srow + (int)wp->w_lsize[j] >= wp->w_height)
        !           350:                                break;
        !           351:                        wp->w_lsize[idx] = wp->w_lsize[j];
        !           352:                        wp->w_lsize_lnum[idx] = lnum++;
        !           353:
        !           354:                        row += wp->w_lsize[idx++];
        !           355:                        if ((int)++j >= wp->w_lsize_valid)
        !           356:                            break;
        !           357:                    }
        !           358:                    wp->w_lsize_valid = idx;
        !           359:                }
        !           360:                else
        !           361:                    row = 0;        /* update all lines */
        !           362:            }
        !           363:        }
        !           364:        if (endrow == wp->w_height && idx == 0)     /* no scrolling */
        !           365:                wp->w_lsize_valid = 0;
        !           366:    }
        !           367:
        !           368:    done = didline = FALSE;
        !           369:
        !           370:    if (VIsual_active)      /* check if we are updating the inverted part */
        !           371:    {
        !           372:        linenr_t    from, to;
        !           373:
        !           374:    /* find the line numbers that need to be updated */
        !           375:        if (curwin->w_cursor.lnum < wp->w_old_cursor_lnum)
        !           376:        {
        !           377:            from = curwin->w_cursor.lnum;
        !           378:            to = wp->w_old_cursor_lnum;
        !           379:        }
        !           380:        else
        !           381:        {
        !           382:            from = wp->w_old_cursor_lnum;
        !           383:            to = curwin->w_cursor.lnum;
        !           384:        }
        !           385:            /* if VIsual changed, update the maximal area */
        !           386:        if (VIsual.lnum != wp->w_old_visual_lnum)
        !           387:        {
        !           388:            if (wp->w_old_visual_lnum < from)
        !           389:                from = wp->w_old_visual_lnum;
        !           390:            if (wp->w_old_visual_lnum > to)
        !           391:                to = wp->w_old_visual_lnum;
        !           392:            if (VIsual.lnum < from)
        !           393:                from = VIsual.lnum;
        !           394:            if (VIsual.lnum > to)
        !           395:                to = VIsual.lnum;
        !           396:        }
        !           397:    /* if in block mode and changed column or wp->w_curswant: update all
        !           398:     * lines */
        !           399:        if (VIsual_mode == Ctrl('V') &&
        !           400:                        (curwin->w_virtcol != wp->w_old_cursor_vcol ||
        !           401:                        wp->w_curswant != wp->w_old_curswant))
        !           402:        {
        !           403:            if (from > VIsual.lnum)
        !           404:                from = VIsual.lnum;
        !           405:            if (to < VIsual.lnum)
        !           406:                to = VIsual.lnum;
        !           407:        }
        !           408:
        !           409:        if (from < wp->w_topline)
        !           410:            from = wp->w_topline;
        !           411:        if (from >= wp->w_botline)
        !           412:            from = wp->w_botline - 1;
        !           413:        if (to >= wp->w_botline)
        !           414:            to = wp->w_botline - 1;
        !           415:
        !           416:    /* find the minimal part to be updated */
        !           417:        if (type == INVERTED)
        !           418:        {
        !           419:            while (lnum < from)                     /* find start */
        !           420:            {
        !           421:                row += wp->w_lsize[idx++];
        !           422:                ++lnum;
        !           423:            }
        !           424:            srow = row;
        !           425:            for (j = idx; j < wp->w_lsize_valid; ++j)   /* find end */
        !           426:            {
        !           427:                if (wp->w_lsize_lnum[j] == to + 1)
        !           428:                {
        !           429:                    endrow = srow;
        !           430:                    break;
        !           431:                }
        !           432:                srow += wp->w_lsize[j];
        !           433:            }
        !           434:        }
        !           435:
        !           436:    /* if we update the lines between from and to set old_cursor */
        !           437:        if (type == INVERTED || (lnum <= from &&
        !           438:                                  (endrow == wp->w_height || lastline >= to)))
        !           439:        {
        !           440:            wp->w_old_cursor_lnum = curwin->w_cursor.lnum;
        !           441:            wp->w_old_cursor_vcol = curwin->w_virtcol;
        !           442:            wp->w_old_visual_lnum = VIsual.lnum;
        !           443:            wp->w_old_curswant = wp->w_curswant;
        !           444:        }
        !           445:    }
        !           446:    else
        !           447:    {
        !           448:        wp->w_old_cursor_lnum = 0;
        !           449:        wp->w_old_visual_lnum = 0;
        !           450:    }
        !           451:
        !           452:    (void)set_highlight('v');
        !           453:
        !           454:    /*
        !           455:     * Update the screen rows from "row" to "endrow".
        !           456:     * Start at line "lnum" which is at wp->w_lsize_lnum[idx].
        !           457:     */
        !           458:    for (;;)
        !           459:    {
        !           460:        if (lnum > wp->w_buffer->b_ml.ml_line_count)
        !           461:        {
        !           462:            done = TRUE;        /* hit the end of the file */
        !           463:            break;
        !           464:        }
        !           465:        srow = row;
        !           466:        row = win_line(wp, lnum, srow, endrow);
        !           467:        if (row > endrow)       /* past end of screen */
        !           468:        {                       /* we may need the size of that */
        !           469:            wp->w_lsize[idx] = plines_win(wp, lnum);
        !           470:            wp->w_lsize_lnum[idx++] = lnum;     /* too long line later on */
        !           471:            break;
        !           472:        }
        !           473:
        !           474:        wp->w_lsize[idx] = row - srow;
        !           475:        wp->w_lsize_lnum[idx++] = lnum;
        !           476:        if (++lnum > wp->w_buffer->b_ml.ml_line_count)
        !           477:        {
        !           478:            done = TRUE;
        !           479:            break;
        !           480:        }
        !           481:
        !           482:        if (row == endrow)
        !           483:        {
        !           484:            didline = TRUE;
        !           485:            break;
        !           486:        }
        !           487:    }
        !           488:    if (idx > wp->w_lsize_valid)
        !           489:        wp->w_lsize_valid = idx;
        !           490:
        !           491:    /* Do we have to do off the top of the screen processing ? */
        !           492:    if (endrow != wp->w_height)
        !           493:    {
        !           494:        row = 0;
        !           495:        for (idx = 0; idx < wp->w_lsize_valid && row < wp->w_height; idx++)
        !           496:            row += wp->w_lsize[idx];
        !           497:
        !           498:        if (row < wp->w_height)
        !           499:        {
        !           500:            done = TRUE;
        !           501:        }
        !           502:        else if (row > wp->w_height)    /* Need to blank out the last line */
        !           503:        {
        !           504:            lnum = wp->w_lsize_lnum[idx - 1];
        !           505:            srow = row - wp->w_lsize[idx - 1];
        !           506:            didline = FALSE;
        !           507:        }
        !           508:        else
        !           509:        {
        !           510:            lnum = wp->w_lsize_lnum[idx - 1] + 1;
        !           511:            didline = TRUE;
        !           512:        }
        !           513:    }
        !           514:
        !           515:    wp->w_empty_rows = 0;
        !           516:    /*
        !           517:     * If we didn't hit the end of the file, and we didn't finish the last
        !           518:     * line we were working on, then the line didn't fit.
        !           519:     */
        !           520:    if (!done && !didline)
        !           521:    {
        !           522:        if (lnum == wp->w_topline)
        !           523:        {
        !           524:            /*
        !           525:             * Single line that does not fit!
        !           526:             * Fill last line with '@' characters.
        !           527:             */
        !           528:            screen_fill(wp->w_winpos + wp->w_height - 1,
        !           529:                    wp->w_winpos + wp->w_height, 0, (int)Columns, '@', '@');
        !           530:            wp->w_botline = lnum + 1;
        !           531:        }
        !           532:        else
        !           533:        {
        !           534:            /*
        !           535:             * Clear the rest of the screen and mark the unused lines.
        !           536:             */
        !           537: #ifdef RIGHTLEFT
        !           538:            if (wp->w_p_rl)
        !           539:                rightleft = 1;
        !           540: #endif
        !           541:            screen_fill(wp->w_winpos + srow,
        !           542:                    wp->w_winpos + wp->w_height, 0, (int)Columns, '@', ' ');
        !           543: #ifdef RIGHTLEFT
        !           544:            rightleft = 0;
        !           545: #endif
        !           546:            wp->w_botline = lnum;
        !           547:            wp->w_empty_rows = wp->w_height - srow;
        !           548:        }
        !           549:    }
        !           550:    else
        !           551:    {
        !           552:        /* make sure the rest of the screen is blank */
        !           553:        /* put '~'s on rows that aren't part of the file. */
        !           554: #ifdef RIGHTLEFT
        !           555:        if (wp->w_p_rl)
        !           556:            rightleft = 1;
        !           557: #endif
        !           558:        screen_fill(wp->w_winpos + row,
        !           559:                    wp->w_winpos + wp->w_height, 0, (int)Columns, '~', ' ');
        !           560: #ifdef RIGHTLEFT
        !           561:        rightleft = 0;
        !           562: #endif
        !           563:        wp->w_empty_rows = wp->w_height - row;
        !           564:
        !           565:        if (done)               /* we hit the end of the file */
        !           566:            wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1;
        !           567:        else
        !           568:            wp->w_botline = lnum;
        !           569:    }
        !           570:
        !           571:    wp->w_redr_type = 0;
        !           572: }
        !           573:
        !           574: /*
        !           575:  * mark all status lines for redraw; used after first :cd
        !           576:  */
        !           577:    void
        !           578: status_redraw_all()
        !           579: {
        !           580:    WIN     *wp;
        !           581:
        !           582:    for (wp = firstwin; wp; wp = wp->w_next)
        !           583:        wp->w_redr_status = TRUE;
        !           584:    updateScreen(NOT_VALID);
        !           585: }
        !           586:
        !           587: /*
        !           588:  * Redraw the status line of window wp.
        !           589:  *
        !           590:  * If inversion is possible we use it. Else '=' characters are used.
        !           591:  */
        !           592:    void
        !           593: win_redr_status(wp)
        !           594:    WIN     *wp;
        !           595: {
        !           596:    int     row;
        !           597:    char_u  *p;
        !           598:    int     len;
        !           599:    int     fillchar;
        !           600:
        !           601:    if (wp->w_status_height)                    /* if there is a status line */
        !           602:    {
        !           603:        if (set_highlight('s') == OK)           /* can highlight */
        !           604:        {
        !           605:            fillchar = ' ';
        !           606:            start_highlight();
        !           607:        }
        !           608:        else                                    /* can't highlight, use '=' */
        !           609:            fillchar = '=';
        !           610:
        !           611:        p = wp->w_buffer->b_xfilename;
        !           612:        if (p == NULL)
        !           613:            STRCPY(NameBuff, "[No File]");
        !           614:        else
        !           615:        {
        !           616:            home_replace(wp->w_buffer, p, NameBuff, MAXPATHL);
        !           617:            trans_characters(NameBuff, MAXPATHL);
        !           618:        }
        !           619:        p = NameBuff;
        !           620:        len = STRLEN(p);
        !           621:
        !           622:        if (wp->w_buffer->b_help || wp->w_buffer->b_changed ||
        !           623:                                                         wp->w_buffer->b_p_ro)
        !           624:            *(p + len++) = ' ';
        !           625:        if (wp->w_buffer->b_help)
        !           626:        {
        !           627:            STRCPY(p + len, "[help]");
        !           628:            len += 6;
        !           629:        }
        !           630:        if (wp->w_buffer->b_changed)
        !           631:        {
        !           632:            STRCPY(p + len, "[+]");
        !           633:            len += 3;
        !           634:        }
        !           635:        if (wp->w_buffer->b_p_ro)
        !           636:        {
        !           637:            STRCPY(p + len, "[RO]");
        !           638:            len += 4;
        !           639:        }
        !           640:
        !           641:        if (len > ru_col - 1)
        !           642:        {
        !           643:            p += len - (ru_col - 1);
        !           644:            *p = '<';
        !           645:            len = ru_col - 1;
        !           646:        }
        !           647:
        !           648:        row = wp->w_winpos + wp->w_height;
        !           649:        screen_msg(p, row, 0);
        !           650:        screen_fill(row, row + 1, len, ru_col, fillchar, fillchar);
        !           651:
        !           652:        stop_highlight();
        !           653:        win_redr_ruler(wp, TRUE);
        !           654:    }
        !           655:    else    /* no status line, can only be last window */
        !           656:        redraw_cmdline = TRUE;
        !           657:    wp->w_redr_status = FALSE;
        !           658: }
        !           659:
        !           660: /*
        !           661:  * display line "lnum" of window 'wp' on the screen
        !           662:  * Start at row "startrow", stop when "endrow" is reached.
        !           663:  * Return the number of last row the line occupies.
        !           664:  */
        !           665:
        !           666:    static int
        !           667: win_line(wp, lnum, startrow, endrow)
        !           668:    WIN             *wp;
        !           669:    linenr_t        lnum;
        !           670:    int             startrow;
        !           671:    int             endrow;
        !           672: {
        !           673:    char_u          *screenp;
        !           674:    int             c;
        !           675:    int             col;                /* visual column on screen */
        !           676:    long            vcol;               /* visual column for tabs */
        !           677:    int             row;                /* row in the window, excl w_winpos */
        !           678:    int             screen_row;         /* row on the screen, incl w_winpos */
        !           679:    char_u          *ptr;
        !           680:    char_u          extra[16];          /* "%ld" must fit in here */
        !           681:    char_u          *p_extra;
        !           682:    char_u          *showbreak = NULL;
        !           683:    int             n_extra;
        !           684:    int             n_spaces = 0;
        !           685:
        !           686:    int             fromcol, tocol;     /* start/end of inverting */
        !           687:    int             noinvcur = FALSE;   /* don't invert the cursor */
        !           688:    FPOS            *top, *bot;
        !           689:
        !           690:    if (startrow > endrow)              /* past the end already! */
        !           691:        return startrow;
        !           692:
        !           693:    row = startrow;
        !           694:    screen_row = row + wp->w_winpos;
        !           695:    col = 0;
        !           696:    vcol = 0;
        !           697:    fromcol = -10;
        !           698:    tocol = MAXCOL;
        !           699:    canopt = TRUE;
        !           700:
        !           701:    /*
        !           702:     * handle visual active in this window
        !           703:     */
        !           704:    if (VIsual_active && wp->w_buffer == curwin->w_buffer)
        !           705:    {
        !           706:                                        /* Visual is after curwin->w_cursor */
        !           707:        if (ltoreq(curwin->w_cursor, VIsual))
        !           708:        {
        !           709:            top = &curwin->w_cursor;
        !           710:            bot = &VIsual;
        !           711:        }
        !           712:        else                            /* Visual is before curwin->w_cursor */
        !           713:        {
        !           714:            top = &VIsual;
        !           715:            bot = &curwin->w_cursor;
        !           716:        }
        !           717:        if (VIsual_mode == Ctrl('V'))   /* block mode */
        !           718:        {
        !           719:            if (lnum >= top->lnum && lnum <= bot->lnum)
        !           720:            {
        !           721:                colnr_t     from, to;
        !           722:
        !           723:                getvcol(wp, top, (colnr_t *)&fromcol, NULL, (colnr_t *)&tocol);
        !           724:                getvcol(wp, bot, &from, NULL, &to);
        !           725:                if ((int)from < fromcol)
        !           726:                    fromcol = from;
        !           727:                if ((int)to > tocol)
        !           728:                    tocol = to;
        !           729:                ++tocol;
        !           730:
        !           731:                if (wp->w_curswant == MAXCOL)
        !           732:                    tocol = MAXCOL;
        !           733:            }
        !           734:        }
        !           735:        else                            /* non-block mode */
        !           736:        {
        !           737:            if (lnum > top->lnum && lnum <= bot->lnum)
        !           738:                fromcol = 0;
        !           739:            else if (lnum == top->lnum)
        !           740:                getvcol(wp, top, (colnr_t *)&fromcol, NULL, NULL);
        !           741:            if (lnum == bot->lnum)
        !           742:            {
        !           743:                getvcol(wp, bot, NULL, NULL, (colnr_t *)&tocol);
        !           744:                ++tocol;
        !           745:            }
        !           746:
        !           747:            if (VIsual_mode == 'V')     /* linewise */
        !           748:            {
        !           749:                if (fromcol > 0)
        !           750:                    fromcol = 0;
        !           751:                tocol = MAXCOL;
        !           752:            }
        !           753:        }
        !           754:            /* if the cursor can't be switched off, don't invert the
        !           755:             * character where the cursor is */
        !           756: #ifndef MSDOS
        !           757:        if (!highlight_match && *T_VI == NUL &&
        !           758:                            lnum == curwin->w_cursor.lnum && wp == curwin)
        !           759:            noinvcur = TRUE;
        !           760: #endif
        !           761:
        !           762:        if (tocol <= (int)wp->w_leftcol)    /* inverting is left of screen */
        !           763:            fromcol = 0;
        !           764:                                        /* start of invert is left of screen */
        !           765:        else if (fromcol >= 0 && fromcol < (int)wp->w_leftcol)
        !           766:            fromcol = wp->w_leftcol;
        !           767:
        !           768:        /* if inverting in this line, can't optimize cursor positioning */
        !           769:        if (fromcol >= 0)
        !           770:            canopt = FALSE;
        !           771:    }
        !           772:    /*
        !           773:     * handle incremental search position highlighting
        !           774:     */
        !           775:    else if (highlight_match && wp == curwin && search_match_len)
        !           776:    {
        !           777:        if (lnum == curwin->w_cursor.lnum)
        !           778:        {
        !           779:            getvcol(curwin, &(curwin->w_cursor),
        !           780:                                            (colnr_t *)&fromcol, NULL, NULL);
        !           781:            curwin->w_cursor.col += search_match_len;
        !           782:            getvcol(curwin, &(curwin->w_cursor),
        !           783:                                            (colnr_t *)&tocol, NULL, NULL);
        !           784:            curwin->w_cursor.col -= search_match_len;
        !           785:            canopt = FALSE;
        !           786:            if (fromcol == tocol)       /* do at least one character */
        !           787:                tocol = fromcol + 1;    /* happens when past end of line */
        !           788:        }
        !           789:    }
        !           790:
        !           791:    ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
        !           792:    if (!wp->w_p_wrap)      /* advance to first character to be displayed */
        !           793:    {
        !           794:        while ((colnr_t)vcol < wp->w_leftcol && *ptr)
        !           795:            vcol += win_chartabsize(wp, *ptr++, (colnr_t)vcol);
        !           796:        if ((colnr_t)vcol > wp->w_leftcol)
        !           797:        {
        !           798:            n_spaces = vcol - wp->w_leftcol;    /* begin with some spaces */
        !           799:            vcol = wp->w_leftcol;
        !           800:        }
        !           801:    }
        !           802:    screenp = LinePointers[screen_row];
        !           803: #ifdef RIGHTLEFT
        !           804:    if (wp->w_p_rl)
        !           805:    {
        !           806:        col = Columns - 1;                  /* col follows screenp here */
        !           807:        screenp += Columns - 1;
        !           808:    }
        !           809: #endif
        !           810:    if (wp->w_p_nu)
        !           811:    {
        !           812: #ifdef RIGHTLEFT
        !           813:         if (wp->w_p_rl)                        /* reverse line numbers */
        !           814:        {
        !           815:            char_u *c1, *c2, t;
        !           816:
        !           817:            sprintf((char *)extra, " %-7ld", (long)lnum);
        !           818:            for (c1 = extra, c2 = extra + STRLEN(extra) - 1; c1 < c2;
        !           819:                                                                   c1++, c2--)
        !           820:            {
        !           821:                t = *c1;
        !           822:                *c1 = *c2;
        !           823:                *c2 = t;
        !           824:            }
        !           825:        }
        !           826:        else
        !           827: #endif
        !           828:            sprintf((char *)extra, "%7ld ", (long)lnum);
        !           829:        p_extra = extra;
        !           830:        n_extra = 8;
        !           831:        vcol -= 8;      /* so vcol is 0 when line number has been printed */
        !           832:    }
        !           833:    else
        !           834:    {
        !           835:        p_extra = NULL;
        !           836:        n_extra = 0;
        !           837:    }
        !           838:    for (;;)
        !           839:    {
        !           840:        if (!canopt)    /* Visual or match highlighting in this line */
        !           841:        {
        !           842:            if (((vcol == fromcol && !(noinvcur &&
        !           843:                                           (colnr_t)vcol == wp->w_virtcol)) ||
        !           844:                    (noinvcur && (colnr_t)vcol == wp->w_virtcol + 1 &&
        !           845:                            vcol >= fromcol)) && vcol < tocol)
        !           846:                start_highlight();      /* start highlighting */
        !           847:            else if (attributes && (vcol == tocol ||
        !           848:                                (noinvcur && (colnr_t)vcol == wp->w_virtcol)))
        !           849:                stop_highlight();       /* stop highlighting */
        !           850:        }
        !           851:
        !           852:    /* Get the next character to put on the screen. */
        !           853:
        !           854:        /*
        !           855:         * if 'showbreak' is set it contains the characters to put at the
        !           856:         * start of each broken line
        !           857:         */
        !           858:        if (
        !           859: #ifdef RIGHTLEFT
        !           860:            (wp->w_p_rl ? col == -1 : col == Columns)
        !           861: #else
        !           862:            col == Columns
        !           863: #endif
        !           864:            && (*ptr != NUL || (wp->w_p_list && n_extra == 0) ||
        !           865:                                        (n_extra && *p_extra) || n_spaces) &&
        !           866:                                              vcol != 0 && STRLEN(p_sbr) != 0)
        !           867:            showbreak = p_sbr;
        !           868:        if (showbreak != NULL)
        !           869:        {
        !           870:            c = *showbreak++;
        !           871:            if (*showbreak == NUL)
        !           872:                showbreak = NULL;
        !           873:        }
        !           874:        /*
        !           875:         * The 'extra' array contains the extra stuff that is inserted to
        !           876:         * represent special characters (non-printable stuff).
        !           877:         */
        !           878:        else if (n_extra)
        !           879:        {
        !           880:            c = *p_extra++;
        !           881:            n_extra--;
        !           882:        }
        !           883:        else if (n_spaces)
        !           884:        {
        !           885:            c = ' ';
        !           886:            n_spaces--;
        !           887:        }
        !           888:        else
        !           889:        {
        !           890:            c = *ptr++;
        !           891:            /*
        !           892:             * Found last space before word: check for line break
        !           893:             */
        !           894:            if (wp->w_p_lbr && isbreak(c) && !isbreak(*ptr) && !wp->w_p_list)
        !           895:            {
        !           896:                n_spaces = win_lbr_chartabsize(wp, ptr - 1,
        !           897:                                                     (colnr_t)vcol, NULL) - 1;
        !           898:                if (vim_iswhite(c))
        !           899:                    c = ' ';
        !           900:            }
        !           901:            else if (!isprintchar(c))
        !           902:            {
        !           903:                /*
        !           904:                 * when getting a character from the file, we may have to turn
        !           905:                 * it into something else on the way to putting it into
        !           906:                 * 'NextScreen'.
        !           907:                 */
        !           908:                if (c == TAB && !wp->w_p_list)
        !           909:                {
        !           910:                    /* tab amount depends on current column */
        !           911:                    n_spaces = (int)wp->w_buffer->b_p_ts -
        !           912:                                    vcol % (int)wp->w_buffer->b_p_ts - 1;
        !           913:                    c = ' ';
        !           914:                }
        !           915:                else if (c == NUL && wp->w_p_list)
        !           916:                {
        !           917:                    p_extra = (char_u *)"";
        !           918:                    n_extra = 1;
        !           919:                    c = '$';
        !           920:                    --ptr;          /* put it back at the NUL */
        !           921:                }
        !           922:                else if (c != NUL)
        !           923:                {
        !           924:                    p_extra = transchar(c);
        !           925:                    n_extra = charsize(c) - 1;
        !           926:                    c = *p_extra++;
        !           927:                }
        !           928:            }
        !           929:        }
        !           930:
        !           931:        if (c == NUL)
        !           932:        {
        !           933:            if (attributes)
        !           934:            {
        !           935:                /* invert at least one char, used for Visual and empty line or
        !           936:                 * highlight match at end of line. If it's beyond the last
        !           937:                 * char on the screen, just overwrite that one (tricky!) */
        !           938:                if (vcol == fromcol)
        !           939:                {
        !           940: #ifdef RIGHTLEFT
        !           941:                    if (wp->w_p_rl)
        !           942:                    {
        !           943:                        if (col < 0)
        !           944:                        {
        !           945:                            ++screenp;
        !           946:                            ++col;
        !           947:                        }
        !           948:                    }
        !           949:                    else
        !           950: #endif
        !           951:                    {
        !           952:                        if (col >= Columns)
        !           953:                        {
        !           954:                            --screenp;
        !           955:                            --col;
        !           956:                        }
        !           957:                    }
        !           958:                    if (*screenp != ' ' || *(screenp + Columns) != attributes)
        !           959:                    {
        !           960:                            *screenp = ' ';
        !           961:                            *(screenp + Columns) = attributes;
        !           962:                            screen_char(screenp, screen_row, col);
        !           963:                    }
        !           964: #ifdef RIGHTLEFT
        !           965:                    if (wp->w_p_rl)
        !           966:                    {
        !           967:                        --screenp;
        !           968:                        --col;
        !           969:                    }
        !           970:                    else
        !           971: #endif
        !           972:                    {
        !           973:                        ++screenp;
        !           974:                        ++col;
        !           975:                    }
        !           976:                }
        !           977:                stop_highlight();
        !           978:            }
        !           979:            /*
        !           980:             * blank out the rest of this row, if necessary
        !           981:             */
        !           982: #ifdef RIGHTLEFT
        !           983:            if (wp->w_p_rl)
        !           984:            {
        !           985:                while (col >= 0 && *screenp == ' ' &&
        !           986:                                                    *(screenp + Columns) == 0)
        !           987:                {
        !           988:                    --screenp;
        !           989:                    --col;
        !           990:                }
        !           991:                if (col >= 0)
        !           992:                    screen_fill(screen_row, screen_row + 1,
        !           993:                                                        0, col + 1, ' ', ' ');
        !           994:            }
        !           995:            else
        !           996: #endif
        !           997:            {
        !           998:                while (col < Columns && *screenp == ' ' &&
        !           999:                                                    *(screenp + Columns) == 0)
        !          1000:                {
        !          1001:                    ++screenp;
        !          1002:                    ++col;
        !          1003:                }
        !          1004:                if (col < Columns)
        !          1005:                    screen_fill(screen_row, screen_row + 1,
        !          1006:                                                col, (int)Columns, ' ', ' ');
        !          1007:            }
        !          1008:            row++;
        !          1009:            break;
        !          1010:        }
        !          1011:        if (
        !          1012: #ifdef RIGHTLEFT
        !          1013:            wp->w_p_rl ? (col < 0) :
        !          1014: #endif
        !          1015:                                    (col >= Columns)
        !          1016:                                                    )
        !          1017:        {
        !          1018:            col = 0;
        !          1019:            ++row;
        !          1020:            ++screen_row;
        !          1021:            if (!wp->w_p_wrap)
        !          1022:                break;
        !          1023:            if (row == endrow)      /* line got too long for screen */
        !          1024:            {
        !          1025:                ++row;
        !          1026:                break;
        !          1027:            }
        !          1028:            screenp = LinePointers[screen_row];
        !          1029: #ifdef RIGHTLEFT
        !          1030:            if (wp->w_p_rl)
        !          1031:            {
        !          1032:                col = Columns - 1;      /* col is not used if breaking! */
        !          1033:                screenp += Columns - 1;
        !          1034:            }
        !          1035: #endif
        !          1036:        }
        !          1037:
        !          1038:        /*
        !          1039:         * Store the character in NextScreen.
        !          1040:         */
        !          1041:        if (*screenp != c || *(screenp + Columns) != attributes)
        !          1042:        {
        !          1043:            /*
        !          1044:             * Special trick to make copy/paste of wrapped lines work with
        !          1045:             * xterm/screen:
        !          1046:             *   If the first column is to be written, write the preceding
        !          1047:             *   char twice.  This will work with all terminal types
        !          1048:             *   (regardless of the xn,am settings).
        !          1049:             * Only do this on a fast tty.
        !          1050:             */
        !          1051:            if (p_tf && row > startrow && col == 0 &&
        !          1052:                    LinePointers[screen_row - 1][Columns - 1 + Columns] ==
        !          1053:                        attributes)
        !          1054:            {
        !          1055:                if (screen_cur_row != screen_row - 1 ||
        !          1056:                                                    screen_cur_col != Columns)
        !          1057:                    screen_char(LinePointers[screen_row - 1] + Columns - 1,
        !          1058:                                          screen_row - 1, (int)(Columns - 1));
        !          1059:                screen_char(LinePointers[screen_row - 1] + Columns - 1,
        !          1060:                                                screen_row - 1, (int)Columns);
        !          1061:                screen_start();
        !          1062:            }
        !          1063:
        !          1064:            *screenp = c;
        !          1065:            *(screenp + Columns) = attributes;
        !          1066:            screen_char(screenp, screen_row, col);
        !          1067:        }
        !          1068: #ifdef RIGHTLEFT
        !          1069:        if (wp->w_p_rl)
        !          1070:        {
        !          1071:            --screenp;
        !          1072:            --col;
        !          1073:        }
        !          1074:        else
        !          1075: #endif
        !          1076:        {
        !          1077:            ++screenp;
        !          1078:            ++col;
        !          1079:        }
        !          1080:        ++vcol;
        !          1081:            /* stop before '$' of change command */
        !          1082:        if (wp == curwin && dollar_vcol && vcol >= (long)wp->w_virtcol)
        !          1083:            break;
        !          1084:    }
        !          1085:
        !          1086:    stop_highlight();
        !          1087:    return (row);
        !          1088: }
        !          1089:
        !          1090: /*
        !          1091:  * Called when p_dollar is set: display a '$' at the end of the changed text
        !          1092:  * Only works when cursor is in the line that changes.
        !          1093:  */
        !          1094:    void
        !          1095: display_dollar(col)
        !          1096:    colnr_t     col;
        !          1097: {
        !          1098:    colnr_t save_col;
        !          1099:
        !          1100:    if (RedrawingDisabled)
        !          1101:        return;
        !          1102:
        !          1103:    cursor_off();
        !          1104:    save_col = curwin->w_cursor.col;
        !          1105:    curwin->w_cursor.col = col;
        !          1106:    curs_columns(FALSE);
        !          1107:    if (!curwin->w_p_wrap)
        !          1108:        curwin->w_col -= curwin->w_leftcol;
        !          1109:    if (curwin->w_col < Columns)
        !          1110:    {
        !          1111:        screen_msg((char_u *)"$", curwin->w_winpos + curwin->w_row,
        !          1112: #ifdef RIGHTLEFT
        !          1113:                curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
        !          1114: #endif
        !          1115:                                                               curwin->w_col);
        !          1116:        dollar_vcol = curwin->w_virtcol;
        !          1117:    }
        !          1118:    curwin->w_cursor.col = save_col;
        !          1119: }
        !          1120:
        !          1121: /*
        !          1122:  * Call this function before moving the cursor from the normal insert position
        !          1123:  * in insert mode.
        !          1124:  */
        !          1125:    void
        !          1126: undisplay_dollar()
        !          1127: {
        !          1128:    if (dollar_vcol)
        !          1129:    {
        !          1130:        dollar_vcol = 0;
        !          1131:        updateline();
        !          1132:    }
        !          1133: }
        !          1134:
        !          1135: /*
        !          1136:  * output a single character directly to the screen
        !          1137:  * update NextScreen
        !          1138:  */
        !          1139:    void
        !          1140: screen_outchar(c, row, col)
        !          1141:    int     c;
        !          1142:    int     row, col;
        !          1143: {
        !          1144:    char_u      buf[2];
        !          1145:
        !          1146:    buf[0] = c;
        !          1147:    buf[1] = NUL;
        !          1148:    screen_msg(buf, row, col);
        !          1149: }
        !          1150:
        !          1151: /*
        !          1152:  * put string '*text' on the screen at position 'row' and 'col'
        !          1153:  * update NextScreen
        !          1154:  * Note: only outputs within one row, message is truncated at screen boundary!
        !          1155:  * Note: if NextScreen, row and/or col is invalid, nothing is done.
        !          1156:  */
        !          1157:    void
        !          1158: screen_msg(text, row, col)
        !          1159:    char_u  *text;
        !          1160:    int     row;
        !          1161:    int     col;
        !          1162: {
        !          1163:    char_u  *screenp;
        !          1164:
        !          1165:    if (NextScreen != NULL && row < Rows)           /* safety check */
        !          1166:    {
        !          1167:        screenp = LinePointers[row] + col;
        !          1168:        while (*text && col < Columns)
        !          1169:        {
        !          1170:            if (*screenp != *text || *(screenp + Columns) != attributes)
        !          1171:            {
        !          1172:                *screenp = *text;
        !          1173:                *(screenp + Columns) = attributes;
        !          1174:                screen_char(screenp, row, col);
        !          1175:            }
        !          1176:            ++screenp;
        !          1177:            ++col;
        !          1178:            ++text;
        !          1179:        }
        !          1180:    }
        !          1181: }
        !          1182:
        !          1183: /*
        !          1184:  * Reset cursor position. Use whenever cursor was moved because of outputting
        !          1185:  * something directly to the screen (shell commands) or a terminal control
        !          1186:  * code.
        !          1187:  */
        !          1188:    void
        !          1189: screen_start()
        !          1190: {
        !          1191:    screen_cur_row = screen_cur_col = 9999;
        !          1192: }
        !          1193:
        !          1194: /*
        !          1195:  * set_highlight - set highlight depending on 'highlight' option and context.
        !          1196:  *
        !          1197:  * return FAIL if highlighting is not possible, OK otherwise
        !          1198:  */
        !          1199:    int
        !          1200: set_highlight(context)
        !          1201:    int     context;
        !          1202: {
        !          1203:    int     i;
        !          1204:    int     mode;
        !          1205:    char_u  *p;
        !          1206:
        !          1207:    /*
        !          1208:     * Try to find the mode in the 'highlight' option.
        !          1209:     * If not found, try the default for the 'highlight' option.
        !          1210:     * If still not found, use 'r' (should not happen).
        !          1211:     */
        !          1212:    mode = 'r';
        !          1213:    for (i = 0; i < 2; ++i)
        !          1214:    {
        !          1215:        if (i)
        !          1216:            p = get_highlight_default();
        !          1217:        else
        !          1218:            p = p_hl;
        !          1219:        if (p == NULL)
        !          1220:            continue;
        !          1221:
        !          1222:        while (*p)
        !          1223:        {
        !          1224:            if (*p == context)              /* found what we are looking for */
        !          1225:                break;
        !          1226:            while (*p && *p != ',')         /* skip to comma */
        !          1227:                ++p;
        !          1228:            p = skip_to_option_part(p);     /* skip comma and spaces */
        !          1229:        }
        !          1230:        if (p[0] && p[1])
        !          1231:        {
        !          1232:            mode = p[1];
        !          1233:            break;
        !          1234:        }
        !          1235:    }
        !          1236:
        !          1237:    switch (mode)
        !          1238:    {
        !          1239:        case 'b':   highlight = T_MD;       /* bold */
        !          1240:                    unhighlight = T_ME;
        !          1241:                    highlight_attr = CHAR_BOLD;
        !          1242:                    break;
        !          1243:        case 's':   highlight = T_SO;       /* standout */
        !          1244:                    unhighlight = T_SE;
        !          1245:                    highlight_attr = CHAR_STDOUT;
        !          1246:                    break;
        !          1247:        case 'n':   highlight = NULL;       /* no highlighting */
        !          1248:                    unhighlight = NULL;
        !          1249:                    highlight_attr = 0;
        !          1250:                    break;
        !          1251:        case 'u':   highlight = T_US;       /* underline */
        !          1252:                    unhighlight = T_UE;
        !          1253:                    highlight_attr = CHAR_UNDERL;
        !          1254:                    break;
        !          1255:        case 'i':   highlight = T_CZH;      /* italic */
        !          1256:                    unhighlight = T_CZR;
        !          1257:                    highlight_attr = CHAR_ITALIC;
        !          1258:                    break;
        !          1259:        default:    highlight = T_MR;       /* reverse (invert) */
        !          1260:                    unhighlight = T_ME;
        !          1261:                    highlight_attr = CHAR_INVERT;
        !          1262:                    break;
        !          1263:    }
        !          1264:    if (highlight == NULL || *highlight == NUL ||
        !          1265:                        unhighlight == NULL || *unhighlight == NUL)
        !          1266:    {
        !          1267:        highlight = NULL;
        !          1268:        return FAIL;
        !          1269:    }
        !          1270:    return OK;
        !          1271: }
        !          1272:
        !          1273:    void
        !          1274: start_highlight()
        !          1275: {
        !          1276:    if (full_screen &&
        !          1277: #ifdef WIN32
        !          1278:                        termcap_active &&
        !          1279: #endif
        !          1280:                                            highlight != NULL)
        !          1281:    {
        !          1282:        outstr(highlight);
        !          1283:        attributes = highlight_attr;
        !          1284:    }
        !          1285: }
        !          1286:
        !          1287:    void
        !          1288: stop_highlight()
        !          1289: {
        !          1290:    if (attributes)
        !          1291:    {
        !          1292:        outstr(unhighlight);
        !          1293:        attributes = 0;
        !          1294:    }
        !          1295: }
        !          1296:
        !          1297: /*
        !          1298:  * variables used for one level depth of highlighting
        !          1299:  * Used for "-- More --" message.
        !          1300:  */
        !          1301:
        !          1302: static char_u  *old_highlight = NULL;
        !          1303: static char_u  *old_unhighlight = NULL;
        !          1304: static int     old_highlight_attr = 0;
        !          1305:
        !          1306:    void
        !          1307: remember_highlight()
        !          1308: {
        !          1309:    old_highlight = highlight;
        !          1310:    old_unhighlight = unhighlight;
        !          1311:    old_highlight_attr = highlight_attr;
        !          1312: }
        !          1313:
        !          1314:    void
        !          1315: recover_old_highlight()
        !          1316: {
        !          1317:    highlight = old_highlight;
        !          1318:    unhighlight = old_unhighlight;
        !          1319:    highlight_attr = old_highlight_attr;
        !          1320: }
        !          1321:
        !          1322: /*
        !          1323:  * put character '*p' on the screen at position 'row' and 'col'
        !          1324:  */
        !          1325:    static void
        !          1326: screen_char(p, row, col)
        !          1327:    char_u  *p;
        !          1328:    int     row;
        !          1329:    int     col;
        !          1330: {
        !          1331:    int         c;
        !          1332:    int         noinvcurs;
        !          1333:
        !          1334:    /*
        !          1335:     * Outputting the last character on the screen may scrollup the screen.
        !          1336:     * Don't to it!
        !          1337:     */
        !          1338:    if (col == Columns - 1 && row == Rows - 1)
        !          1339:        return;
        !          1340:    if (screen_cur_col != col || screen_cur_row != row)
        !          1341:    {
        !          1342:        /* check if no cursor movement is allowed in standout mode */
        !          1343:        if (attributes && !p_wiv && *T_MS == NUL)
        !          1344:            noinvcurs = 7;
        !          1345:        else
        !          1346:            noinvcurs = 0;
        !          1347:
        !          1348:        /*
        !          1349:         * If we're on the same row (which happens a lot!), try to
        !          1350:         * avoid a windgoto().
        !          1351:         * If we are only a few characters off, output the
        !          1352:         * characters. That is faster than cursor positioning.
        !          1353:         * This can't be used when switching between inverting and not
        !          1354:         * inverting.
        !          1355:         */
        !          1356:        if (screen_cur_row == row && screen_cur_col < col)
        !          1357:        {
        !          1358:            register int i;
        !          1359:
        !          1360:            i = col - screen_cur_col;
        !          1361:            if (i <= 4 + noinvcurs)
        !          1362:            {
        !          1363:                /* stop at the first character that has different attributes
        !          1364:                 * from the ones that are active */
        !          1365:                while (i && *(p - i + Columns) == attributes)
        !          1366:                {
        !          1367:                    c = *(p - i--);
        !          1368:                    outchar(c);
        !          1369:                }
        !          1370:            }
        !          1371:            if (i)
        !          1372:            {
        !          1373:                if (noinvcurs)
        !          1374:                    stop_highlight();
        !          1375:
        !          1376:                if (*T_CRI != NUL)  /* use tgoto interface! jw */
        !          1377:                    OUTSTR(tgoto((char *)T_CRI, 0, i));
        !          1378:                else
        !          1379:                    windgoto(row, col);
        !          1380:
        !          1381:                if (noinvcurs)
        !          1382:                    start_highlight();
        !          1383:            }
        !          1384:        }
        !          1385:        /*
        !          1386:         * If the cursor is at the line above where we want to be, use CR LF,
        !          1387:         * this is quicker than windgoto().
        !          1388:         * Don't do this if the cursor went beyond the last column, the cursor
        !          1389:         * position is unknown then (some terminals wrap, some don't )
        !          1390:         */
        !          1391:        else if (screen_cur_row + 1 == row && col == 0 &&
        !          1392:                                                     screen_cur_col < Columns)
        !          1393:        {
        !          1394:            if (noinvcurs)
        !          1395:                stop_highlight();
        !          1396:            outchar('\n');
        !          1397:            if (noinvcurs)
        !          1398:                start_highlight();
        !          1399:        }
        !          1400:        else
        !          1401:        {
        !          1402:            if (noinvcurs)
        !          1403:                stop_highlight();
        !          1404:            windgoto(row, col);
        !          1405:            if (noinvcurs)
        !          1406:                start_highlight();
        !          1407:        }
        !          1408:        screen_cur_row = row;
        !          1409:        screen_cur_col = col;
        !          1410:    }
        !          1411:
        !          1412:    /*
        !          1413:     * For weird invert mechanism: output (un)highlight before every char
        !          1414:     * Lots of extra output, but works.
        !          1415:     */
        !          1416:    if (p_wiv)
        !          1417:    {
        !          1418:        if (attributes)
        !          1419:            outstr(highlight);
        !          1420:        else if (full_screen)
        !          1421:            outstr(unhighlight);
        !          1422:    }
        !          1423:    outchar(*p);
        !          1424:    screen_cur_col++;
        !          1425: }
        !          1426:
        !          1427: /*
        !          1428:  * Fill the screen from 'start_row' to 'end_row', from 'start_col' to 'end_col'
        !          1429:  * with character 'c1' in first column followed by 'c2' in the other columns.
        !          1430:  */
        !          1431:    void
        !          1432: screen_fill(start_row, end_row, start_col, end_col, c1, c2)
        !          1433:    int     start_row, end_row;
        !          1434:    int     start_col, end_col;
        !          1435:    int     c1, c2;
        !          1436: {
        !          1437:    int             row;
        !          1438:    int             col;
        !          1439:    char_u          *screenp;
        !          1440:    char_u          *attrp;
        !          1441:    int             did_delete;
        !          1442:    int             c;
        !          1443:
        !          1444:    if (end_row > Rows)             /* safety check */
        !          1445:        end_row = Rows;
        !          1446:    if (end_col > Columns)          /* safety check */
        !          1447:        end_col = Columns;
        !          1448:    if (NextScreen == NULL ||
        !          1449:            start_row >= end_row || start_col >= end_col)   /* nothing to do */
        !          1450:        return;
        !          1451:
        !          1452:    for (row = start_row; row < end_row; ++row)
        !          1453:    {
        !          1454:            /* try to use delete-line termcap code */
        !          1455:        did_delete = FALSE;
        !          1456:        if (attributes == 0 && c2 == ' ' && end_col == Columns && *T_CE != NUL
        !          1457: #ifdef RIGHTLEFT
        !          1458:                    && !rightleft
        !          1459: #endif
        !          1460:                                    )
        !          1461:        {
        !          1462:            /*
        !          1463:             * check if we really need to clear something
        !          1464:             */
        !          1465:            col = start_col;
        !          1466:            screenp = LinePointers[row] + start_col;
        !          1467:            if (c1 != ' ')                      /* don't clear first char */
        !          1468:            {
        !          1469:                ++col;
        !          1470:                ++screenp;
        !          1471:            }
        !          1472:
        !          1473:            /* skip blanks (used often, keep it fast!) */
        !          1474:            attrp = screenp + Columns;
        !          1475:            while (col < end_col && *screenp == ' ' && *attrp == 0)
        !          1476:            {
        !          1477:                ++col;
        !          1478:                ++screenp;
        !          1479:                ++attrp;
        !          1480:            }
        !          1481:            if (col < end_col)          /* something to be cleared */
        !          1482:            {
        !          1483:                windgoto(row, col);     /* clear rest of this screen line */
        !          1484:                outstr(T_CE);
        !          1485:                screen_start();         /* don't know where cursor is now */
        !          1486:                col = end_col - col;
        !          1487:                while (col--)           /* clear chars in NextScreen */
        !          1488:                {
        !          1489:                    *attrp++ = 0;
        !          1490:                    *screenp++ = ' ';
        !          1491:                }
        !          1492:            }
        !          1493:            did_delete = TRUE;          /* the chars are cleared now */
        !          1494:        }
        !          1495:
        !          1496:        screenp = LinePointers[row] +
        !          1497: #ifdef RIGHTLEFT
        !          1498:            (rightleft ? (int)Columns - 1 - start_col : start_col);
        !          1499: #else
        !          1500:                                                    start_col;
        !          1501: #endif
        !          1502:        c = c1;
        !          1503:        for (col = start_col; col < end_col; ++col)
        !          1504:        {
        !          1505:            if (*screenp != c || *(screenp + Columns) != attributes)
        !          1506:            {
        !          1507:                *screenp = c;
        !          1508:                *(screenp + Columns) = attributes;
        !          1509:                if (!did_delete || c != ' ')
        !          1510:                    screen_char(screenp, row,
        !          1511: #ifdef RIGHTLEFT
        !          1512:                            rightleft ? Columns - 1 - col :
        !          1513: #endif
        !          1514:                                                            col);
        !          1515:            }
        !          1516: #ifdef RIGHTLEFT
        !          1517:            if (rightleft)
        !          1518:                --screenp;
        !          1519:            else
        !          1520: #endif
        !          1521:                ++screenp;
        !          1522:            if (col == start_col)
        !          1523:            {
        !          1524:                if (did_delete)
        !          1525:                    break;
        !          1526:                c = c2;
        !          1527:            }
        !          1528:        }
        !          1529:        if (row == Rows - 1)            /* overwritten the command line */
        !          1530:        {
        !          1531:            redraw_cmdline = TRUE;
        !          1532:            if (c1 == ' ' && c2 == ' ')
        !          1533:                clear_cmdline = FALSE;  /* command line has been cleared */
        !          1534:        }
        !          1535:    }
        !          1536: }
        !          1537:
        !          1538: /*
        !          1539:  * recompute all w_botline's. Called after Rows changed.
        !          1540:  */
        !          1541:    void
        !          1542: comp_Botline_all()
        !          1543: {
        !          1544:    WIN     *wp;
        !          1545:
        !          1546:    for (wp = firstwin; wp; wp = wp->w_next)
        !          1547:        comp_Botline(wp);
        !          1548: }
        !          1549:
        !          1550: /*
        !          1551:  * compute wp->w_botline. Can be called after wp->w_topline changed.
        !          1552:  */
        !          1553:    void
        !          1554: comp_Botline(wp)
        !          1555:    WIN         *wp;
        !          1556: {
        !          1557:    comp_Botline_sub(wp, wp->w_topline, 0);
        !          1558: }
        !          1559:
        !          1560: /*
        !          1561:  * Compute wp->w_botline, may have a start at the cursor position.
        !          1562:  * Code shared between comp_Botline() and cursupdate().
        !          1563:  */
        !          1564:    static void
        !          1565: comp_Botline_sub(wp, lnum, done)
        !          1566:    WIN         *wp;
        !          1567:    linenr_t    lnum;
        !          1568:    int         done;
        !          1569: {
        !          1570:    int         n;
        !          1571:
        !          1572:    for ( ; lnum <= wp->w_buffer->b_ml.ml_line_count; ++lnum)
        !          1573:    {
        !          1574:        n = plines_win(wp, lnum);
        !          1575:        if (done + n > wp->w_height)
        !          1576:            break;
        !          1577:        done += n;
        !          1578:    }
        !          1579:
        !          1580:    /* wp->w_botline is the line that is just below the window */
        !          1581:    wp->w_botline = lnum;
        !          1582:
        !          1583:    /* Also set wp->w_empty_rows, otherwise scroll_cursor_bot() won't work */
        !          1584:    if (done == 0)
        !          1585:        wp->w_empty_rows = 0;       /* single line that doesn't fit */
        !          1586:    else
        !          1587:        wp->w_empty_rows = wp->w_height - done;
        !          1588: }
        !          1589:
        !          1590:    void
        !          1591: screenalloc(clear)
        !          1592:    int     clear;
        !          1593: {
        !          1594:    register int    new_row, old_row;
        !          1595:    WIN             *wp;
        !          1596:    int             outofmem = FALSE;
        !          1597:    int             len;
        !          1598:    char_u          *new_NextScreen;
        !          1599:    char_u          **new_LinePointers;
        !          1600:
        !          1601:    /*
        !          1602:     * Allocation of the screen buffers is done only when the size changes
        !          1603:     * and when Rows and Columns have been set and we are doing full screen
        !          1604:     * stuff.
        !          1605:     */
        !          1606:    if ((NextScreen != NULL && Rows == screen_Rows && Columns == screen_Columns)
        !          1607:                            || Rows == 0 || Columns == 0 || !full_screen)
        !          1608:        return;
        !          1609:
        !          1610:    comp_col();         /* recompute columns for shown command and ruler */
        !          1611:
        !          1612:    /*
        !          1613:     * We're changing the size of the screen.
        !          1614:     * - Allocate new arrays for NextScreen.
        !          1615:     * - Move lines from the old arrays into the new arrays, clear extra
        !          1616:     *   lines (unless the screen is going to be cleared).
        !          1617:     * - Free the old arrays.
        !          1618:     */
        !          1619:    for (wp = firstwin; wp; wp = wp->w_next)
        !          1620:        win_free_lsize(wp);
        !          1621:
        !          1622:    new_NextScreen = (char_u *)malloc((size_t) (Rows * Columns * 2));
        !          1623:    new_LinePointers = (char_u **)malloc(sizeof(char_u *) * Rows);
        !          1624:
        !          1625:    for (wp = firstwin; wp; wp = wp->w_next)
        !          1626:    {
        !          1627:        if (win_alloc_lsize(wp) == FAIL)
        !          1628:        {
        !          1629:            outofmem = TRUE;
        !          1630:            break;
        !          1631:        }
        !          1632:    }
        !          1633:
        !          1634:    if (new_NextScreen == NULL || new_LinePointers == NULL || outofmem)
        !          1635:    {
        !          1636:        do_outofmem_msg();
        !          1637:        vim_free(new_NextScreen);
        !          1638:        new_NextScreen = NULL;
        !          1639:    }
        !          1640:    else
        !          1641:    {
        !          1642:        for (new_row = 0; new_row < Rows; ++new_row)
        !          1643:        {
        !          1644:            new_LinePointers[new_row] = new_NextScreen + new_row * Columns * 2;
        !          1645:
        !          1646:            /*
        !          1647:             * If the screen is not going to be cleared, copy as much as
        !          1648:             * possible from the old screen to the new one and clear the rest
        !          1649:             * (used when resizing the window at the "--more--" prompt or when
        !          1650:             * executing an external command, for the GUI).
        !          1651:             */
        !          1652:            if (!clear)
        !          1653:            {
        !          1654:                lineclear(new_LinePointers[new_row]);
        !          1655:                old_row = new_row + (screen_Rows - Rows);
        !          1656:                if (old_row >= 0)
        !          1657:                {
        !          1658:                    if (screen_Columns < Columns)
        !          1659:                        len = screen_Columns;
        !          1660:                    else
        !          1661:                        len = Columns;
        !          1662:                    vim_memmove(new_LinePointers[new_row],
        !          1663:                            LinePointers[old_row], (size_t)len);
        !          1664:                    vim_memmove(new_LinePointers[new_row] + Columns,
        !          1665:                            LinePointers[old_row] + screen_Columns, (size_t)len);
        !          1666:                }
        !          1667:            }
        !          1668:        }
        !          1669:    }
        !          1670:
        !          1671:    vim_free(NextScreen);
        !          1672:    vim_free(LinePointers);
        !          1673:    NextScreen = new_NextScreen;
        !          1674:    LinePointers = new_LinePointers;
        !          1675:
        !          1676:    must_redraw = CLEAR;        /* need to clear the screen later */
        !          1677:    if (clear)
        !          1678:        screenclear2();
        !          1679:
        !          1680: #ifdef USE_GUI
        !          1681:    else if (gui.in_use && NextScreen != NULL && Rows != screen_Rows)
        !          1682:    {
        !          1683:        gui_redraw_block(0, 0, Rows - 1, Columns - 1);
        !          1684:        /*
        !          1685:         * Adjust the position of the cursor, for when executing an external
        !          1686:         * command.
        !          1687:         */
        !          1688:        if (msg_row >= Rows)                /* Rows got smaller */
        !          1689:            msg_row = Rows - 1;             /* put cursor at last row */
        !          1690:        else if (Rows > screen_Rows)        /* Rows got bigger */
        !          1691:            msg_row += Rows - screen_Rows;  /* put cursor in same place */
        !          1692:        if (msg_col >= Columns)             /* Columns got smaller */
        !          1693:            msg_col = Columns - 1;          /* put cursor at last column */
        !          1694:    }
        !          1695: #endif
        !          1696:
        !          1697:    screen_Rows = Rows;
        !          1698:    screen_Columns = Columns;
        !          1699: }
        !          1700:
        !          1701:    void
        !          1702: screenclear()
        !          1703: {
        !          1704:    if (emsg_on_display)
        !          1705:    {
        !          1706:        mch_delay(1000L, TRUE);
        !          1707:        emsg_on_display = FALSE;
        !          1708:    }
        !          1709:    screenalloc(FALSE);     /* allocate screen buffers if size changed */
        !          1710:    screenclear2();         /* clear the screen */
        !          1711: }
        !          1712:
        !          1713:    static void
        !          1714: screenclear2()
        !          1715: {
        !          1716:    int     i;
        !          1717:
        !          1718:    if (starting || NextScreen == NULL)
        !          1719:        return;
        !          1720:
        !          1721:    outstr(T_CL);               /* clear the display */
        !          1722:
        !          1723:                                /* blank out NextScreen */
        !          1724:    for (i = 0; i < Rows; ++i)
        !          1725:        lineclear(LinePointers[i]);
        !          1726:
        !          1727:    screen_cleared = TRUE;          /* can use contents of NextScreen now */
        !          1728:
        !          1729:    win_rest_invalid(firstwin);
        !          1730:    clear_cmdline = FALSE;
        !          1731:    redraw_cmdline = TRUE;
        !          1732:    if (must_redraw == CLEAR)       /* no need to clear again */
        !          1733:        must_redraw = NOT_VALID;
        !          1734:    compute_cmdrow();
        !          1735:    msg_pos((int)Rows - 1, 0);      /* put cursor on last line for messages */
        !          1736:    screen_start();                 /* don't know where cursor is now */
        !          1737:    msg_scrolled = 0;               /* can't scroll back */
        !          1738:    msg_didany = FALSE;
        !          1739:    msg_didout = FALSE;
        !          1740: }
        !          1741:
        !          1742: /*
        !          1743:  * Clear one line in NextScreen.
        !          1744:  */
        !          1745:    static void
        !          1746: lineclear(p)
        !          1747:    char_u  *p;
        !          1748: {
        !          1749:    (void)vim_memset(p, ' ', (size_t)Columns);
        !          1750:    (void)vim_memset(p + Columns, 0, (size_t)Columns);
        !          1751: }
        !          1752:
        !          1753: /*
        !          1754:  * check cursor for a valid lnum
        !          1755:  */
        !          1756:    void
        !          1757: check_cursor()
        !          1758: {
        !          1759:    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
        !          1760:        curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          1761:    if (curwin->w_cursor.lnum <= 0)
        !          1762:        curwin->w_cursor.lnum = 1;
        !          1763: }
        !          1764:
        !          1765:    void
        !          1766: cursupdate()
        !          1767: {
        !          1768:    linenr_t        lnum;
        !          1769:    long            line_count;
        !          1770:    int             sline;
        !          1771:    int             done;
        !          1772:    int             temp;
        !          1773:
        !          1774:    if (!screen_valid(TRUE))
        !          1775:        return;
        !          1776:
        !          1777:    /*
        !          1778:     * Make sure the cursor is on a valid line number
        !          1779:     */
        !          1780:    check_cursor();
        !          1781:
        !          1782:    /*
        !          1783:     * If the buffer is empty, always set topline to 1.
        !          1784:     */
        !          1785:    if (bufempty())             /* special case - file is empty */
        !          1786:    {
        !          1787:        curwin->w_topline = 1;
        !          1788:        curwin->w_cursor.lnum = 1;
        !          1789:        curwin->w_cursor.col = 0;
        !          1790:        curwin->w_lsize[0] = 0;
        !          1791:        if (curwin->w_lsize_valid == 0) /* don't know about screen contents */
        !          1792:            updateScreen(NOT_VALID);
        !          1793:        curwin->w_lsize_valid = 1;
        !          1794:    }
        !          1795:
        !          1796:    /*
        !          1797:     * If the cursor is above the top of the window, scroll the window to put
        !          1798:     * it at the top of the window.
        !          1799:     * If we weren't very close to begin with, we scroll to put the cursor in
        !          1800:     * the middle of the window.
        !          1801:     */
        !          1802:    else if (curwin->w_cursor.lnum < curwin->w_topline + p_so &&
        !          1803:                                                        curwin->w_topline > 1)
        !          1804:    {
        !          1805:        temp = curwin->w_height / 2 - 1;
        !          1806:        if (temp < 2)
        !          1807:            temp = 2;
        !          1808:                                /* not very close, put cursor halfway screen */
        !          1809:        if (curwin->w_topline + p_so - curwin->w_cursor.lnum >= temp)
        !          1810:            scroll_cursor_halfway(FALSE);
        !          1811:        else
        !          1812:            scroll_cursor_top((int)p_sj, FALSE);
        !          1813:        updateScreen(VALID);
        !          1814:    }
        !          1815:
        !          1816:    /*
        !          1817:     * If the cursor is below the bottom of the window, scroll the window
        !          1818:     * to put the cursor on the window. If the cursor is less than a
        !          1819:     * windowheight down compute the number of lines at the top which have
        !          1820:     * the same or more rows than the rows of the lines below the bottom.
        !          1821:     * Note: After curwin->w_botline was computed lines may have been
        !          1822:     * added or deleted, it may be greater than ml_line_count.
        !          1823:     */
        !          1824:    else if ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so &&
        !          1825:                                curwin->w_botline <= curbuf->b_ml.ml_line_count)
        !          1826:    {
        !          1827:        line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so;
        !          1828:        if (line_count <= curwin->w_height + 1)
        !          1829:            scroll_cursor_bot((int)p_sj, FALSE);
        !          1830:        else
        !          1831:            scroll_cursor_halfway(FALSE);
        !          1832:        updateScreen(VALID);
        !          1833:    }
        !          1834:
        !          1835:    /*
        !          1836:     * If the window contents is unknown, need to update the screen.
        !          1837:     */
        !          1838:    else if (curwin->w_lsize_valid == 0)
        !          1839:        updateScreen(NOT_VALID);
        !          1840:
        !          1841:    /*
        !          1842:     * Figure out the row number of the cursor line.
        !          1843:     * This is used often, keep it fast!
        !          1844:     */
        !          1845:    curwin->w_row = sline = 0;
        !          1846:                                            /* curwin->w_lsize[] invalid */
        !          1847:    if (RedrawingDisabled || curwin->w_lsize_valid == 0)
        !          1848:    {
        !          1849:        done = 0;
        !          1850:        for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
        !          1851:            done += plines(lnum);
        !          1852:        curwin->w_row = done;
        !          1853:
        !          1854:        /*
        !          1855:         * Also need to compute w_botline and w_empty_rows, because
        !          1856:         * updateScreen() will not have done that.
        !          1857:         */
        !          1858:        comp_Botline_sub(curwin, lnum, done);
        !          1859:    }
        !          1860:    else
        !          1861:    {
        !          1862:        for (done = curwin->w_cursor.lnum - curwin->w_topline; done > 0; --done)
        !          1863:            curwin->w_row += curwin->w_lsize[sline++];
        !          1864:    }
        !          1865:
        !          1866:    curwin->w_cline_row = curwin->w_row;
        !          1867:    curwin->w_col = curwin->w_virtcol = 0;
        !          1868:    if (!RedrawingDisabled && sline > curwin->w_lsize_valid)
        !          1869:                                /* Should only happen with a line that is too */
        !          1870:                                /* long to fit on the last screen line. */
        !          1871:        curwin->w_cline_height = 0;
        !          1872:    else
        !          1873:    {
        !          1874:                            /* curwin->w_lsize[] invalid */
        !          1875:        if (RedrawingDisabled || curwin->w_lsize_valid == 0)
        !          1876:            curwin->w_cline_height = plines(curwin->w_cursor.lnum);
        !          1877:         else
        !          1878:            curwin->w_cline_height = curwin->w_lsize[sline];
        !          1879:                            /* compute curwin->w_virtcol and curwin->w_col */
        !          1880:        curs_columns(!RedrawingDisabled);
        !          1881:        if (must_redraw)
        !          1882:            updateScreen(must_redraw);
        !          1883:    }
        !          1884:
        !          1885:    if (curwin->w_set_curswant)
        !          1886:    {
        !          1887:        curwin->w_curswant = curwin->w_virtcol;
        !          1888:        curwin->w_set_curswant = FALSE;
        !          1889:    }
        !          1890: }
        !          1891:
        !          1892: /*
        !          1893:  * Recompute topline to put the cursor at the top of the window.
        !          1894:  * Scroll at least "min_scroll" lines.
        !          1895:  * If "always" is TRUE, always set topline (for "zt").
        !          1896:  */
        !          1897:    void
        !          1898: scroll_cursor_top(min_scroll, always)
        !          1899:    int     min_scroll;
        !          1900:    int     always;
        !          1901: {
        !          1902:    int     scrolled = 0;
        !          1903:    int     extra = 0;
        !          1904:    int     used;
        !          1905:    int     i;
        !          1906:    int     sline;      /* screen line for cursor */
        !          1907:
        !          1908:    /*
        !          1909:     * Decrease topline until:
        !          1910:     * - it has become 1
        !          1911:     * - (part of) the cursor line is moved off the screen or
        !          1912:     * - moved at least 'scrolljump' lines and
        !          1913:     * - at least 'scrolloff' lines above and below the cursor
        !          1914:     */
        !          1915:    used = plines(curwin->w_cursor.lnum);
        !          1916:    for (sline = 1; sline < curwin->w_cursor.lnum; ++sline)
        !          1917:    {
        !          1918:        i = plines(curwin->w_cursor.lnum - sline);
        !          1919:        used += i;
        !          1920:        extra += i;
        !          1921:        if (extra <= p_so &&
        !          1922:                   curwin->w_cursor.lnum + sline < curbuf->b_ml.ml_line_count)
        !          1923:            used += plines(curwin->w_cursor.lnum + sline);
        !          1924:        if (used > curwin->w_height)
        !          1925:            break;
        !          1926:        if (curwin->w_cursor.lnum - sline < curwin->w_topline)
        !          1927:            scrolled += i;
        !          1928:
        !          1929:        /*
        !          1930:         * If scrolling is needed, scroll at least 'sj' lines.
        !          1931:         */
        !          1932:        if ((curwin->w_cursor.lnum - (sline - 1) >= curwin->w_topline ||
        !          1933:                                      scrolled >= min_scroll) && extra > p_so)
        !          1934:            break;
        !          1935:    }
        !          1936:
        !          1937:    /*
        !          1938:     * If we don't have enough space, put cursor in the middle.
        !          1939:     * This makes sure we get the same position when using "k" and "j"
        !          1940:     * in a small window.
        !          1941:     */
        !          1942:    if (used > curwin->w_height)
        !          1943:        scroll_cursor_halfway(FALSE);
        !          1944:    else
        !          1945:    {
        !          1946:        /*
        !          1947:         * If "always" is FALSE, only adjust topline to a lower value, higher
        !          1948:         * value may happen with wrapping lines
        !          1949:         */
        !          1950:        if (curwin->w_cursor.lnum - (sline - 1) < curwin->w_topline || always)
        !          1951:            curwin->w_topline = curwin->w_cursor.lnum - (sline - 1);
        !          1952:        if (curwin->w_topline > curwin->w_cursor.lnum)
        !          1953:            curwin->w_topline = curwin->w_cursor.lnum;
        !          1954:    }
        !          1955: }
        !          1956:
        !          1957: /*
        !          1958:  * Recompute topline to put the cursor at the bottom of the window.
        !          1959:  * Scroll at least "min_scroll" lines.
        !          1960:  * If "set_topline" is TRUE, set topline and botline first (for "zb").
        !          1961:  * This is messy stuff!!!
        !          1962:  */
        !          1963:    void
        !          1964: scroll_cursor_bot(min_scroll, set_topline)
        !          1965:    int     min_scroll;
        !          1966:    int     set_topline;
        !          1967: {
        !          1968:    int         used;
        !          1969:    int         scrolled = 0;
        !          1970:    int         extra = 0;
        !          1971:    int         sline;          /* screen line for cursor from bottom */
        !          1972:    int         i;
        !          1973:    linenr_t    lnum;
        !          1974:    linenr_t    line_count;
        !          1975:    linenr_t    old_topline = curwin->w_topline;
        !          1976:    linenr_t    old_botline = curwin->w_botline;
        !          1977:    int         old_empty_rows = curwin->w_empty_rows;
        !          1978:    linenr_t    cln;                /* Cursor Line Number */
        !          1979:
        !          1980:    cln = curwin->w_cursor.lnum;
        !          1981:    if (set_topline)
        !          1982:    {
        !          1983:        used = 0;
        !          1984:        curwin->w_botline = cln + 1;
        !          1985:        for (curwin->w_topline = curwin->w_botline;
        !          1986:                curwin->w_topline != 1;
        !          1987:                --curwin->w_topline)
        !          1988:        {
        !          1989:            i = plines(curwin->w_topline - 1);
        !          1990:            if (used + i > curwin->w_height)
        !          1991:                break;
        !          1992:            used += i;
        !          1993:        }
        !          1994:        curwin->w_empty_rows = curwin->w_height - used;
        !          1995:    }
        !          1996:
        !          1997:    used = plines(cln);
        !          1998:    if (cln >= curwin->w_botline)
        !          1999:    {
        !          2000:        scrolled = used;
        !          2001:        if (cln == curwin->w_botline)
        !          2002:            scrolled -= curwin->w_empty_rows;
        !          2003:    }
        !          2004:
        !          2005:    /*
        !          2006:     * Stop counting lines to scroll when
        !          2007:     * - hitting start of the file
        !          2008:     * - scrolled nothing or at least 'sj' lines
        !          2009:     * - at least 'so' lines below the cursor
        !          2010:     * - lines between botline and cursor have been counted
        !          2011:     */
        !          2012:    for (sline = 1; sline < cln; ++sline)
        !          2013:    {
        !          2014:        if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= p_so) ||
        !          2015:                cln + sline > curbuf->b_ml.ml_line_count) &&
        !          2016:                cln - sline < curwin->w_botline)
        !          2017:            break;
        !          2018:        i = plines(cln - sline);
        !          2019:        used += i;
        !          2020:        if (used > curwin->w_height)
        !          2021:            break;
        !          2022:        if (cln - sline >= curwin->w_botline)
        !          2023:        {
        !          2024:            scrolled += i;
        !          2025:            if (cln - sline == curwin->w_botline)
        !          2026:                scrolled -= curwin->w_empty_rows;
        !          2027:        }
        !          2028:        if (cln + sline <= curbuf->b_ml.ml_line_count)
        !          2029:        {
        !          2030:            i = plines(cln + sline);
        !          2031:            used += i;
        !          2032:            if (used > curwin->w_height)
        !          2033:                break;
        !          2034:            if (extra < p_so || scrolled < min_scroll)
        !          2035:            {
        !          2036:                extra += i;
        !          2037:                if (cln + sline >= curwin->w_botline)
        !          2038:                {
        !          2039:                    scrolled += i;
        !          2040:                    if (cln + sline == curwin->w_botline)
        !          2041:                        scrolled -= curwin->w_empty_rows;
        !          2042:                }
        !          2043:            }
        !          2044:        }
        !          2045:    }
        !          2046:    /* curwin->w_empty_rows is larger, no need to scroll */
        !          2047:    if (scrolled <= 0)
        !          2048:        line_count = 0;
        !          2049:    /* more than a screenfull, don't scroll but redraw */
        !          2050:    else if (used > curwin->w_height)
        !          2051:        line_count = used;
        !          2052:    /* scroll minimal number of lines */
        !          2053:    else
        !          2054:    {
        !          2055:        for (i = 0, lnum = curwin->w_topline;
        !          2056:                i < scrolled && lnum < curwin->w_botline; ++lnum)
        !          2057:            i += plines(lnum);
        !          2058:        if (i >= scrolled)      /* it's possible to scroll */
        !          2059:            line_count = lnum - curwin->w_topline;
        !          2060:        else                /* below curwin->w_botline, don't scroll */
        !          2061:            line_count = 9999;
        !          2062:    }
        !          2063:
        !          2064:    /*
        !          2065:     * Scroll up if the cursor is off the bottom of the screen a bit.
        !          2066:     * Otherwise put it at 1/2 of the screen.
        !          2067:     */
        !          2068:    if (line_count >= curwin->w_height && line_count > min_scroll)
        !          2069:        scroll_cursor_halfway(FALSE);
        !          2070:    else
        !          2071:        scrollup(line_count);
        !          2072:
        !          2073:    /*
        !          2074:     * If topline didn't change we need to restore w_botline and w_empty_rows
        !          2075:     * (we changed them).
        !          2076:     * If topline did change, updateScreen() will set botline.
        !          2077:     */
        !          2078:    if (curwin->w_topline == old_topline && set_topline)
        !          2079:    {
        !          2080:        curwin->w_botline = old_botline;
        !          2081:        curwin->w_empty_rows = old_empty_rows;
        !          2082:    }
        !          2083: }
        !          2084:
        !          2085: /*
        !          2086:  * Recompute topline to put the cursor halfway the window
        !          2087:  * If "atend" is TRUE, also put it halfway at the end of the file.
        !          2088:  */
        !          2089:    void
        !          2090: scroll_cursor_halfway(atend)
        !          2091:    int     atend;
        !          2092: {
        !          2093:    int         above = 0;
        !          2094:    linenr_t    topline;
        !          2095:    int         below = 0;
        !          2096:    linenr_t    botline;
        !          2097:    int         used;
        !          2098:    int         i;
        !          2099:    linenr_t    cln;                /* Cursor Line Number */
        !          2100:
        !          2101:    topline = botline = cln = curwin->w_cursor.lnum;
        !          2102:    used = plines(cln);
        !          2103:    while (topline > 1)
        !          2104:    {
        !          2105:        if (below <= above)         /* add a line below the cursor */
        !          2106:        {
        !          2107:            if (botline + 1 <= curbuf->b_ml.ml_line_count)
        !          2108:            {
        !          2109:                i = plines(botline + 1);
        !          2110:                used += i;
        !          2111:                if (used > curwin->w_height)
        !          2112:                    break;
        !          2113:                below += i;
        !          2114:                ++botline;
        !          2115:            }
        !          2116:            else
        !          2117:            {
        !          2118:                ++below;            /* count a "~" line */
        !          2119:                if (atend)
        !          2120:                    ++used;
        !          2121:            }
        !          2122:        }
        !          2123:
        !          2124:        if (below > above)          /* add a line above the cursor */
        !          2125:        {
        !          2126:            i = plines(topline - 1);
        !          2127:            used += i;
        !          2128:            if (used > curwin->w_height)
        !          2129:                break;
        !          2130:            above += i;
        !          2131:            --topline;
        !          2132:        }
        !          2133:    }
        !          2134:    curwin->w_topline = topline;
        !          2135: }
        !          2136:
        !          2137: /*
        !          2138:  * Correct the cursor position so that it is in a part of the screen at least
        !          2139:  * 'so' lines from the top and bottom, if possible.
        !          2140:  * If not possible, put it at the same position as scroll_cursor_halfway().
        !          2141:  * When called topline and botline must be valid!
        !          2142:  */
        !          2143:    void
        !          2144: cursor_correct()
        !          2145: {
        !          2146:    int         above = 0;          /* screen lines above topline */
        !          2147:    linenr_t    topline;
        !          2148:    int         below = 0;          /* screen lines below botline */
        !          2149:    linenr_t    botline;
        !          2150:    int         above_wanted, below_wanted;
        !          2151:    linenr_t    cln;                /* Cursor Line Number */
        !          2152:    int         max_off;
        !          2153:
        !          2154:    /*
        !          2155:     * How many lines we would like to have above/below the cursor depends on
        !          2156:     * whether the first/last line of the file is on screen.
        !          2157:     */
        !          2158:    above_wanted = p_so;
        !          2159:    below_wanted = p_so;
        !          2160:    if (curwin->w_topline == 1)
        !          2161:    {
        !          2162:        above_wanted = 0;
        !          2163:        max_off = curwin->w_height / 2;
        !          2164:        if (below_wanted > max_off)
        !          2165:            below_wanted = max_off;
        !          2166:    }
        !          2167:    if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1)
        !          2168:    {
        !          2169:        below_wanted = 0;
        !          2170:        max_off = (curwin->w_height - 1) / 2;
        !          2171:        if (above_wanted > max_off)
        !          2172:            above_wanted = max_off;
        !          2173:    }
        !          2174:
        !          2175:    /*
        !          2176:     * If there are sufficient file-lines above and below the cursor, we can
        !          2177:     * return now.
        !          2178:     */
        !          2179:    cln = curwin->w_cursor.lnum;
        !          2180:    if (cln >= curwin->w_topline + above_wanted &&
        !          2181:                                      cln < curwin->w_botline - below_wanted)
        !          2182:        return;
        !          2183:
        !          2184:    /*
        !          2185:     * Narrow down the area where the cursor can be put by taking lines from
        !          2186:     * the top and the bottom until:
        !          2187:     * - the desired context lines are found
        !          2188:     * - the lines from the top is past the lines from the bottom
        !          2189:     */
        !          2190:    topline = curwin->w_topline;
        !          2191:    botline = curwin->w_botline - 1;
        !          2192:    while ((above < above_wanted || below < below_wanted) && topline < botline)
        !          2193:    {
        !          2194:        if (below < below_wanted && (below <= above || above >= above_wanted))
        !          2195:        {
        !          2196:            below += plines(botline);
        !          2197:            --botline;
        !          2198:        }
        !          2199:        if (above < above_wanted && (above < below || below >= below_wanted))
        !          2200:        {
        !          2201:            above += plines(topline);
        !          2202:            ++topline;
        !          2203:        }
        !          2204:    }
        !          2205:    if (topline == botline || botline == 0)
        !          2206:        curwin->w_cursor.lnum = topline;
        !          2207:    else if (topline > botline)
        !          2208:        curwin->w_cursor.lnum = botline;
        !          2209:    else
        !          2210:    {
        !          2211:        if (cln < topline && curwin->w_topline > 1)
        !          2212:            curwin->w_cursor.lnum = topline;
        !          2213:        if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
        !          2214:            curwin->w_cursor.lnum = botline;
        !          2215:    }
        !          2216: }
        !          2217:
        !          2218: /*
        !          2219:  * Compute curwin->w_row.
        !          2220:  * Can be called when topline and botline have not been updated.
        !          2221:  * return OK when cursor is in the window, FAIL when it isn't.
        !          2222:  */
        !          2223:    int
        !          2224: curs_rows()
        !          2225: {
        !          2226:    linenr_t    lnum;
        !          2227:    int         i;
        !          2228:
        !          2229:    if (curwin->w_cursor.lnum < curwin->w_topline ||
        !          2230:                         curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count ||
        !          2231:                                   curwin->w_cursor.lnum >= curwin->w_botline)
        !          2232:        return FAIL;
        !          2233:
        !          2234:    curwin->w_row = i = 0;
        !          2235:    for (lnum = curwin->w_topline; lnum != curwin->w_cursor.lnum; ++lnum)
        !          2236:        if (RedrawingDisabled)      /* curwin->w_lsize[] invalid */
        !          2237:            curwin->w_row += plines(lnum);
        !          2238:        else
        !          2239:            curwin->w_row += curwin->w_lsize[i++];
        !          2240:    return OK;
        !          2241: }
        !          2242:
        !          2243: /*
        !          2244:  * compute curwin->w_col and curwin->w_virtcol
        !          2245:  */
        !          2246:    void
        !          2247: curs_columns(scroll)
        !          2248:    int scroll;         /* when TRUE, may scroll horizontally */
        !          2249: {
        !          2250:    int     diff;
        !          2251:    int     extra;
        !          2252:    int     new_leftcol;
        !          2253:    colnr_t startcol;
        !          2254:    colnr_t endcol;
        !          2255:
        !          2256:    getvcol(curwin, &curwin->w_cursor,
        !          2257:                                &startcol, &(curwin->w_virtcol), &endcol);
        !          2258:
        !          2259:        /* remove '$' from change command when cursor moves onto it */
        !          2260:    if (startcol > dollar_vcol)
        !          2261:        dollar_vcol = 0;
        !          2262:
        !          2263:    curwin->w_col = curwin->w_virtcol;
        !          2264:    if (curwin->w_p_nu)
        !          2265:    {
        !          2266:        curwin->w_col += 8;
        !          2267:        endcol += 8;
        !          2268:    }
        !          2269:
        !          2270:    curwin->w_row = curwin->w_cline_row;
        !          2271:    if (curwin->w_p_wrap)       /* long line wrapping, adjust curwin->w_row */
        !          2272:    {
        !          2273:        while (curwin->w_col >= Columns)
        !          2274:        {
        !          2275:            curwin->w_col -= Columns;
        !          2276:            curwin->w_row++;
        !          2277:        }
        !          2278:    }
        !          2279:    else if (scroll)    /* no line wrapping, compute curwin->w_leftcol if
        !          2280:                         * scrolling is on.  If scrolling is off,
        !          2281:                         * curwin->w_leftcol is assumed to be 0 */
        !          2282:    {
        !          2283:                        /* If Cursor is left of the screen, scroll rightwards */
        !          2284:                        /* If Cursor is right of the screen, scroll leftwards */
        !          2285:        if ((extra = (int)startcol - (int)curwin->w_leftcol) < 0 ||
        !          2286:             (extra = (int)endcol - (int)(curwin->w_leftcol + Columns) + 1) > 0)
        !          2287:        {
        !          2288:            if (extra < 0)
        !          2289:                diff = -extra;
        !          2290:            else
        !          2291:                diff = extra;
        !          2292:
        !          2293:                /* far off, put cursor in middle of window */
        !          2294:            if (p_ss == 0 || diff >= Columns / 2)
        !          2295:                new_leftcol = curwin->w_col - Columns / 2;
        !          2296:            else
        !          2297:            {
        !          2298:                if (diff < p_ss)
        !          2299:                    diff = p_ss;
        !          2300:                if (extra < 0)
        !          2301:                    new_leftcol = curwin->w_leftcol - diff;
        !          2302:                else
        !          2303:                    new_leftcol = curwin->w_leftcol + diff;
        !          2304:            }
        !          2305:            if (new_leftcol < 0)
        !          2306:                curwin->w_leftcol = 0;
        !          2307:            else
        !          2308:                curwin->w_leftcol = new_leftcol;
        !          2309:                    /* screen has to be redrawn with new curwin->w_leftcol */
        !          2310:            redraw_later(NOT_VALID);
        !          2311:        }
        !          2312:        curwin->w_col -= curwin->w_leftcol;
        !          2313:    }
        !          2314:        /* Cursor past end of screen */
        !          2315:        /* happens with line that does not fit on screen */
        !          2316:    if (curwin->w_row > curwin->w_height - 1)
        !          2317:        curwin->w_row = curwin->w_height - 1;
        !          2318: }
        !          2319:
        !          2320:    void
        !          2321: scrolldown(line_count)
        !          2322:    long    line_count;
        !          2323: {
        !          2324:    register long   done = 0;   /* total # of physical lines done */
        !          2325:
        !          2326:    /* Scroll up 'line_count' lines. */
        !          2327:    while (line_count--)
        !          2328:    {
        !          2329:        if (curwin->w_topline == 1)
        !          2330:            break;
        !          2331:        done += plines(--curwin->w_topline);
        !          2332:    }
        !          2333:    /*
        !          2334:     * Compute the row number of the last row of the cursor line
        !          2335:     * and move it onto the screen.
        !          2336:     */
        !          2337:    curwin->w_row += done;
        !          2338:    if (curwin->w_p_wrap)
        !          2339:        curwin->w_row += plines(curwin->w_cursor.lnum) -
        !          2340:                                              1 - curwin->w_virtcol / Columns;
        !          2341:    while (curwin->w_row >= curwin->w_height && curwin->w_cursor.lnum > 1)
        !          2342:        curwin->w_row -= plines(curwin->w_cursor.lnum--);
        !          2343:    comp_Botline(curwin);
        !          2344: }
        !          2345:
        !          2346:    void
        !          2347: scrollup(line_count)
        !          2348:    long    line_count;
        !          2349: {
        !          2350:    curwin->w_topline += line_count;
        !          2351:    if (curwin->w_topline > curbuf->b_ml.ml_line_count)
        !          2352:        curwin->w_topline = curbuf->b_ml.ml_line_count;
        !          2353:    if (curwin->w_cursor.lnum < curwin->w_topline)
        !          2354:        curwin->w_cursor.lnum = curwin->w_topline;
        !          2355:    comp_Botline(curwin);
        !          2356: }
        !          2357:
        !          2358: /*
        !          2359:  * Scroll the screen one line down, but don't do it if it would move the
        !          2360:  * cursor off the screen.
        !          2361:  */
        !          2362:    void
        !          2363: scrolldown_clamp()
        !          2364: {
        !          2365:    int     end_row;
        !          2366:
        !          2367:    if (curwin->w_topline == 1)
        !          2368:        return;
        !          2369:
        !          2370:    /*
        !          2371:     * Compute the row number of the last row of the cursor line
        !          2372:     * and make sure it doesn't go off the screen. Make sure the cursor
        !          2373:     * doesn't go past 'scrolloff' lines from the screen end.
        !          2374:     */
        !          2375:    end_row = curwin->w_row + plines(curwin->w_topline - 1);
        !          2376:    if (curwin->w_p_wrap)
        !          2377:        end_row += plines(curwin->w_cursor.lnum) - 1 -
        !          2378:                                                  curwin->w_virtcol / Columns;
        !          2379:    if (end_row < curwin->w_height - p_so)
        !          2380:        --curwin->w_topline;
        !          2381: }
        !          2382:
        !          2383: /*
        !          2384:  * Scroll the screen one line up, but don't do it if it would move the cursor
        !          2385:  * off the screen.
        !          2386:  */
        !          2387:    void
        !          2388: scrollup_clamp()
        !          2389: {
        !          2390:    int     start_row;
        !          2391:
        !          2392:    if (curwin->w_topline == curbuf->b_ml.ml_line_count)
        !          2393:        return;
        !          2394:
        !          2395:    /*
        !          2396:     * Compute the row number of the first row of the cursor line
        !          2397:     * and make sure it doesn't go off the screen. Make sure the cursor
        !          2398:     * doesn't go before 'scrolloff' lines from the screen start.
        !          2399:     */
        !          2400:    start_row = curwin->w_row - plines(curwin->w_topline);
        !          2401:    if (curwin->w_p_wrap)
        !          2402:        start_row -= curwin->w_virtcol / Columns;
        !          2403:    if (start_row >= p_so)
        !          2404:        ++curwin->w_topline;
        !          2405: }
        !          2406:
        !          2407: /*
        !          2408:  * insert 'line_count' lines at 'row' in window 'wp'
        !          2409:  * if 'invalid' is TRUE the wp->w_lsize_lnum[] is invalidated.
        !          2410:  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
        !          2411:  * scrolling.
        !          2412:  * Returns FAIL if the lines are not inserted, OK for success.
        !          2413:  */
        !          2414:    int
        !          2415: win_ins_lines(wp, row, line_count, invalid, mayclear)
        !          2416:    WIN     *wp;
        !          2417:    int     row;
        !          2418:    int     line_count;
        !          2419:    int     invalid;
        !          2420:    int     mayclear;
        !          2421: {
        !          2422:    int     did_delete;
        !          2423:    int     nextrow;
        !          2424:    int     lastrow;
        !          2425:    int     retval;
        !          2426:
        !          2427:    if (invalid)
        !          2428:        wp->w_lsize_valid = 0;
        !          2429:
        !          2430:    if (RedrawingDisabled || line_count <= 0 || wp->w_height < 5)
        !          2431:        return FAIL;
        !          2432:
        !          2433:    if (line_count > wp->w_height - row)
        !          2434:        line_count = wp->w_height - row;
        !          2435:
        !          2436:    if (mayclear && Rows - line_count < 5)  /* only a few lines left: redraw is faster */
        !          2437:    {
        !          2438:        screenclear();      /* will set wp->w_lsize_valid to 0 */
        !          2439:        return FAIL;
        !          2440:    }
        !          2441:
        !          2442:    /*
        !          2443:     * Delete all remaining lines
        !          2444:     */
        !          2445:    if (row + line_count >= wp->w_height)
        !          2446:    {
        !          2447:        screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
        !          2448:                                                   0, (int)Columns, ' ', ' ');
        !          2449:        return OK;
        !          2450:    }
        !          2451:
        !          2452:    /*
        !          2453:     * when scrolling, the message on the command line should be cleared,
        !          2454:     * otherwise it will stay there forever.
        !          2455:     */
        !          2456:    clear_cmdline = TRUE;
        !          2457:
        !          2458:    /*
        !          2459:     * if the terminal can set a scroll region, use that
        !          2460:     */
        !          2461:    if (scroll_region)
        !          2462:    {
        !          2463:        scroll_region_set(wp, row);
        !          2464:        retval = screen_ins_lines(wp->w_winpos + row, 0, line_count,
        !          2465:                                                          wp->w_height - row);
        !          2466:        scroll_region_reset();
        !          2467:        return retval;
        !          2468:    }
        !          2469:
        !          2470:    if (wp->w_next && p_tf)     /* don't delete/insert on fast terminal */
        !          2471:        return FAIL;
        !          2472:
        !          2473:    /*
        !          2474:     * If there is a next window or a status line, we first try to delete the
        !          2475:     * lines at the bottom to avoid messing what is after the window.
        !          2476:     * If this fails and there are following windows, don't do anything to avoid
        !          2477:     * messing up those windows, better just redraw.
        !          2478:     */
        !          2479:    did_delete = FALSE;
        !          2480:    if (wp->w_next || wp->w_status_height)
        !          2481:    {
        !          2482:        if (screen_del_lines(0, wp->w_winpos + wp->w_height - line_count,
        !          2483:                                          line_count, (int)Rows, FALSE) == OK)
        !          2484:            did_delete = TRUE;
        !          2485:        else if (wp->w_next)
        !          2486:            return FAIL;
        !          2487:    }
        !          2488:    /*
        !          2489:     * if no lines deleted, blank the lines that will end up below the window
        !          2490:     */
        !          2491:    if (!did_delete)
        !          2492:    {
        !          2493:        wp->w_redr_status = TRUE;
        !          2494:        redraw_cmdline = TRUE;
        !          2495:        nextrow = wp->w_winpos + wp->w_height + wp->w_status_height;
        !          2496:        lastrow = nextrow + line_count;
        !          2497:        if (lastrow > Rows)
        !          2498:            lastrow = Rows;
        !          2499:        screen_fill(nextrow - line_count, lastrow - line_count,
        !          2500:                                                   0, (int)Columns, ' ', ' ');
        !          2501:    }
        !          2502:
        !          2503:    if (screen_ins_lines(0, wp->w_winpos + row, line_count, (int)Rows) == FAIL)
        !          2504:    {
        !          2505:            /* deletion will have messed up other windows */
        !          2506:        if (did_delete)
        !          2507:        {
        !          2508:            wp->w_redr_status = TRUE;
        !          2509:            win_rest_invalid(wp->w_next);
        !          2510:        }
        !          2511:        return FAIL;
        !          2512:    }
        !          2513:
        !          2514:    return OK;
        !          2515: }
        !          2516:
        !          2517: /*
        !          2518:  * delete 'line_count' lines at 'row' in window 'wp'
        !          2519:  * If 'invalid' is TRUE curwin->w_lsize_lnum[] is invalidated.
        !          2520:  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
        !          2521:  * scrolling
        !          2522:  * Return OK for success, FAIL if the lines are not deleted.
        !          2523:  */
        !          2524:    int
        !          2525: win_del_lines(wp, row, line_count, invalid, mayclear)
        !          2526:    WIN             *wp;
        !          2527:    int             row;
        !          2528:    int             line_count;
        !          2529:    int             invalid;
        !          2530:    int             mayclear;
        !          2531: {
        !          2532:    int         retval;
        !          2533:
        !          2534:    if (invalid)
        !          2535:        wp->w_lsize_valid = 0;
        !          2536:
        !          2537:    if (RedrawingDisabled || line_count <= 0)
        !          2538:        return FAIL;
        !          2539:
        !          2540:    if (line_count > wp->w_height - row)
        !          2541:        line_count = wp->w_height - row;
        !          2542:
        !          2543:    /* only a few lines left: redraw is faster */
        !          2544:    if (mayclear && Rows - line_count < 5)
        !          2545:    {
        !          2546:        screenclear();      /* will set wp->w_lsize_valid to 0 */
        !          2547:        return FAIL;
        !          2548:    }
        !          2549:
        !          2550:    /*
        !          2551:     * Delete all remaining lines
        !          2552:     */
        !          2553:    if (row + line_count >= wp->w_height)
        !          2554:    {
        !          2555:        screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
        !          2556:                                                   0, (int)Columns, ' ', ' ');
        !          2557:        return OK;
        !          2558:    }
        !          2559:
        !          2560:    /*
        !          2561:     * when scrolling, the message on the command line should be cleared,
        !          2562:     * otherwise it will stay there forever.
        !          2563:     */
        !          2564:    clear_cmdline = TRUE;
        !          2565:
        !          2566:    /*
        !          2567:     * if the terminal can set a scroll region, use that
        !          2568:     */
        !          2569:    if (scroll_region)
        !          2570:    {
        !          2571:        scroll_region_set(wp, row);
        !          2572:        retval = screen_del_lines(wp->w_winpos + row, 0, line_count,
        !          2573:                                                   wp->w_height - row, FALSE);
        !          2574:        scroll_region_reset();
        !          2575:        return retval;
        !          2576:    }
        !          2577:
        !          2578:    if (wp->w_next && p_tf)     /* don't delete/insert on fast terminal */
        !          2579:        return FAIL;
        !          2580:
        !          2581:    if (screen_del_lines(0, wp->w_winpos + row, line_count,
        !          2582:                                                    (int)Rows, FALSE) == FAIL)
        !          2583:        return FAIL;
        !          2584:
        !          2585:    /*
        !          2586:     * If there are windows or status lines below, try to put them at the
        !          2587:     * correct place. If we can't do that, they have to be redrawn.
        !          2588:     */
        !          2589:    if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
        !          2590:    {
        !          2591:        if (screen_ins_lines(0, wp->w_winpos + wp->w_height - line_count,
        !          2592:                                               line_count, (int)Rows) == FAIL)
        !          2593:        {
        !          2594:            wp->w_redr_status = TRUE;
        !          2595:            win_rest_invalid(wp->w_next);
        !          2596:        }
        !          2597:    }
        !          2598:    /*
        !          2599:     * If this is the last window and there is no status line, redraw the
        !          2600:     * command line later.
        !          2601:     */
        !          2602:    else
        !          2603:        redraw_cmdline = TRUE;
        !          2604:    return OK;
        !          2605: }
        !          2606:
        !          2607: /*
        !          2608:  * window 'wp' and everything after it is messed up, mark it for redraw
        !          2609:  */
        !          2610:    void
        !          2611: win_rest_invalid(wp)
        !          2612:    WIN         *wp;
        !          2613: {
        !          2614:    while (wp)
        !          2615:    {
        !          2616:        wp->w_lsize_valid = 0;
        !          2617:        wp->w_redr_type = NOT_VALID;
        !          2618:        wp->w_redr_status = TRUE;
        !          2619:        wp = wp->w_next;
        !          2620:    }
        !          2621:    redraw_cmdline = TRUE;
        !          2622: }
        !          2623:
        !          2624: /*
        !          2625:  * The rest of the routines in this file perform screen manipulations. The
        !          2626:  * given operation is performed physically on the screen. The corresponding
        !          2627:  * change is also made to the internal screen image. In this way, the editor
        !          2628:  * anticipates the effect of editing changes on the appearance of the screen.
        !          2629:  * That way, when we call screenupdate a complete redraw isn't usually
        !          2630:  * necessary. Another advantage is that we can keep adding code to anticipate
        !          2631:  * screen changes, and in the meantime, everything still works.
        !          2632:  */
        !          2633:
        !          2634: /*
        !          2635:  * types for inserting or deleting lines
        !          2636:  */
        !          2637: #define USE_T_CAL  1
        !          2638: #define USE_T_CDL  2
        !          2639: #define USE_T_AL   3
        !          2640: #define USE_T_CE   4
        !          2641: #define USE_T_DL   5
        !          2642: #define USE_T_SR   6
        !          2643: #define USE_NL     7
        !          2644: #define USE_T_CD   8
        !          2645:
        !          2646: /*
        !          2647:  * insert lines on the screen and update NextScreen
        !          2648:  * 'end' is the line after the scrolled part. Normally it is Rows.
        !          2649:  * When scrolling region used 'off' is the offset from the top for the region.
        !          2650:  * 'row' and 'end' are relative to the start of the region.
        !          2651:  *
        !          2652:  * return FAIL for failure, OK for success.
        !          2653:  */
        !          2654:    static int
        !          2655: screen_ins_lines(off, row, line_count, end)
        !          2656:    int         off;
        !          2657:    int         row;
        !          2658:    int         line_count;
        !          2659:    int         end;
        !          2660: {
        !          2661:    int         i;
        !          2662:    int         j;
        !          2663:    char_u      *temp;
        !          2664:    int         cursor_row;
        !          2665:    int         type;
        !          2666:    int         result_empty;
        !          2667:
        !          2668:    /*
        !          2669:     * FAIL if
        !          2670:     * - there is no valid screen
        !          2671:     * - the screen has to be redrawn completely
        !          2672:     * - the line count is less than one
        !          2673:     * - the line count is more than 'ttyscroll'
        !          2674:     */
        !          2675:    if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
        !          2676:        return FAIL;
        !          2677:
        !          2678:    /*
        !          2679:     * There are seven ways to insert lines:
        !          2680:     * 1. Use T_CD (clear to end of display) if it exists and the result of
        !          2681:     *    the insert is just empty lines
        !          2682:     * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
        !          2683:     *    present or line_count > 1. It looks better if we do all the inserts
        !          2684:     *    at once.
        !          2685:     * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
        !          2686:     *    insert is just empty lines and T_CE is not present or line_count >
        !          2687:     *    1.
        !          2688:     * 4. Use T_AL (insert line) if it exists.
        !          2689:     * 5. Use T_CE (erase line) if it exists and the result of the insert is
        !          2690:     *    just empty lines.
        !          2691:     * 6. Use T_DL (delete line) if it exists and the result of the insert is
        !          2692:     *    just empty lines.
        !          2693:     * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
        !          2694:     *    the 'da' flag is not set or we have clear line capability.
        !          2695:     *
        !          2696:     * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
        !          2697:     * the scrollbar for the window. It does have insert line, use that if it
        !          2698:     * exists.
        !          2699:     */
        !          2700:    result_empty = (row + line_count >= end);
        !          2701:    if (*T_CD != NUL && result_empty)
        !          2702:        type = USE_T_CD;
        !          2703:    else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
        !          2704:        type = USE_T_CAL;
        !          2705:    else if (*T_CDL != NUL && result_empty && (line_count > 1 || *T_CE == NUL))
        !          2706:        type = USE_T_CDL;
        !          2707:    else if (*T_AL != NUL)
        !          2708:        type = USE_T_AL;
        !          2709:    else if (*T_CE != NUL && result_empty)
        !          2710:        type = USE_T_CE;
        !          2711:    else if (*T_DL != NUL && result_empty)
        !          2712:        type = USE_T_DL;
        !          2713:    else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || *T_CE))
        !          2714:        type = USE_T_SR;
        !          2715:    else
        !          2716:        return FAIL;
        !          2717:
        !          2718:    /*
        !          2719:     * For clearing the lines screen_del_lines is used. This will also take
        !          2720:     * care of t_db if necessary.
        !          2721:     */
        !          2722:    if (type == USE_T_CD || type == USE_T_CDL ||
        !          2723:                                         type == USE_T_CE || type == USE_T_DL)
        !          2724:        return screen_del_lines(off, row, line_count, end, FALSE);
        !          2725:
        !          2726:    /*
        !          2727:     * If text is retained below the screen, first clear or delete as many
        !          2728:     * lines at the bottom of the window as are about to be inserted so that
        !          2729:     * the deleted lines won't later surface during a screen_del_lines.
        !          2730:     */
        !          2731:    if (*T_DB)
        !          2732:        screen_del_lines(off, end - line_count, line_count, end, FALSE);
        !          2733:
        !          2734:    if (*T_CSC != NUL)     /* cursor relative to region */
        !          2735:        cursor_row = row;
        !          2736:    else
        !          2737:        cursor_row = row + off;
        !          2738:
        !          2739:    /*
        !          2740:     * Shift LinePointers line_count down to reflect the inserted lines.
        !          2741:     * Clear the inserted lines in NextScreen.
        !          2742:     */
        !          2743:    row += off;
        !          2744:    end += off;
        !          2745:    for (i = 0; i < line_count; ++i)
        !          2746:    {
        !          2747:        j = end - 1 - i;
        !          2748:        temp = LinePointers[j];
        !          2749:        while ((j -= line_count) >= row)
        !          2750:            LinePointers[j + line_count] = LinePointers[j];
        !          2751:        LinePointers[j + line_count] = temp;
        !          2752:        lineclear(temp);
        !          2753:    }
        !          2754:
        !          2755:     windgoto(cursor_row, 0);
        !          2756:     if (type == USE_T_CAL)
        !          2757:    {
        !          2758:        OUTSTR(tgoto((char *)T_CAL, 0, line_count));
        !          2759:        screen_start();         /* don't know where cursor is now */
        !          2760:    }
        !          2761:     else
        !          2762:    {
        !          2763:         for (i = 0; i < line_count; i++)
        !          2764:         {
        !          2765:            if (type == USE_T_AL)
        !          2766:            {
        !          2767:                if (i && cursor_row != 0)
        !          2768:                    windgoto(cursor_row, 0);
        !          2769:                outstr(T_AL);
        !          2770:            }
        !          2771:            else  /* type == USE_T_SR */
        !          2772:                outstr(T_SR);
        !          2773:            screen_start();         /* don't know where cursor is now */
        !          2774:         }
        !          2775:     }
        !          2776:
        !          2777:    /*
        !          2778:     * With scroll-reverse and 'da' flag set we need to clear the lines that
        !          2779:     * have been scrolled down into the region.
        !          2780:     */
        !          2781:    if (type == USE_T_SR && *T_DA)
        !          2782:    {
        !          2783:         for (i = 0; i < line_count; ++i)
        !          2784:         {
        !          2785:            windgoto(off + i, 0);
        !          2786:            outstr(T_CE);
        !          2787:            screen_start();         /* don't know where cursor is now */
        !          2788:        }
        !          2789:    }
        !          2790:
        !          2791:    return OK;
        !          2792: }
        !          2793:
        !          2794: /*
        !          2795:  * delete lines on the screen and update NextScreen
        !          2796:  * 'end' is the line after the scrolled part. Normally it is Rows.
        !          2797:  * When scrolling region used 'off' is the offset from the top for the region.
        !          2798:  * 'row' and 'end' are relative to the start of the region.
        !          2799:  *
        !          2800:  * Return OK for success, FAIL if the lines are not deleted.
        !          2801:  */
        !          2802:    int
        !          2803: screen_del_lines(off, row, line_count, end, force)
        !          2804:    int             off;
        !          2805:    int             row;
        !          2806:    int             line_count;
        !          2807:    int             end;
        !          2808:    int             force;      /* even when line_count > p_ttyscroll */
        !          2809: {
        !          2810:    int         j;
        !          2811:    int         i;
        !          2812:    char_u      *temp;
        !          2813:    int         cursor_row;
        !          2814:    int         cursor_end;
        !          2815:    int         result_empty;   /* result is empty until end of region */
        !          2816:    int         can_delete;     /* deleting line codes can be used */
        !          2817:    int         type;
        !          2818:
        !          2819:    /*
        !          2820:     * FAIL if
        !          2821:     * - there is no valid screen
        !          2822:     * - the screen has to be redrawn completely
        !          2823:     * - the line count is less than one
        !          2824:     * - the line count is more than 'ttyscroll'
        !          2825:     */
        !          2826:    if (!screen_valid(TRUE) || line_count <= 0 ||
        !          2827:                                         (!force && line_count > p_ttyscroll))
        !          2828:        return FAIL;
        !          2829:
        !          2830:    /*
        !          2831:     * Check if the rest of the current region will become empty.
        !          2832:     */
        !          2833:    result_empty = row + line_count >= end;
        !          2834:
        !          2835:    /*
        !          2836:     * We can delete lines only when 'db' flag not set or when 'ce' option
        !          2837:     * available.
        !          2838:     */
        !          2839:    can_delete = (*T_DB == NUL || *T_CE);
        !          2840:
        !          2841:    /*
        !          2842:     * There are four ways to delete lines:
        !          2843:     * 1. Use T_CD if it exists and the result is empty.
        !          2844:     * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
        !          2845:     * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
        !          2846:     *    none of the other ways work.
        !          2847:     * 4. Use T_CE (erase line) if the result is empty.
        !          2848:     * 5. Use T_DL (delete line) if it exists.
        !          2849:     */
        !          2850:    if (*T_CD != NUL && result_empty)
        !          2851:        type = USE_T_CD;
        !          2852:    else if (row == 0 && (line_count == 1 || *T_CDL == NUL))
        !          2853:        type = USE_NL;
        !          2854:    else if (*T_CDL != NUL && line_count > 1 && can_delete)
        !          2855:        type = USE_T_CDL;
        !          2856:    else if (*T_CE != NUL && result_empty)
        !          2857:        type = USE_T_CE;
        !          2858:    else if (*T_DL != NUL && can_delete)
        !          2859:        type = USE_T_DL;
        !          2860:    else if (*T_CDL != NUL && can_delete)
        !          2861:        type = USE_T_CDL;
        !          2862:    else
        !          2863:        return FAIL;
        !          2864:
        !          2865:    if (*T_CSC != NUL)      /* cursor relative to region */
        !          2866:    {
        !          2867:        cursor_row = row;
        !          2868:        cursor_end = end;
        !          2869:    }
        !          2870:    else
        !          2871:    {
        !          2872:        cursor_row = row + off;
        !          2873:        cursor_end = end + off;
        !          2874:    }
        !          2875:
        !          2876:    /*
        !          2877:     * Now shift LinePointers line_count up to reflect the deleted lines.
        !          2878:     * Clear the inserted lines in NextScreen.
        !          2879:     */
        !          2880:    row += off;
        !          2881:    end += off;
        !          2882:    for (i = 0; i < line_count; ++i)
        !          2883:    {
        !          2884:        j = row + i;
        !          2885:        temp = LinePointers[j];
        !          2886:        while ((j += line_count) <= end - 1)
        !          2887:            LinePointers[j - line_count] = LinePointers[j];
        !          2888:        LinePointers[j - line_count] = temp;
        !          2889:        lineclear(temp);
        !          2890:    }
        !          2891:
        !          2892:    /* delete the lines */
        !          2893:    if (type == USE_T_CD)
        !          2894:    {
        !          2895:        windgoto(cursor_row, 0);
        !          2896:        outstr(T_CD);
        !          2897:        screen_start();                 /* don't know where cursor is now */
        !          2898:    }
        !          2899:    else if (type == USE_T_CDL)
        !          2900:    {
        !          2901:        windgoto(cursor_row, 0);
        !          2902:        OUTSTR(tgoto((char *)T_CDL, 0, line_count));
        !          2903:        screen_start();                 /* don't know where cursor is now */
        !          2904:    }
        !          2905:        /*
        !          2906:         * Deleting lines at top of the screen or scroll region: Just scroll
        !          2907:         * the whole screen (scroll region) up by outputting newlines on the
        !          2908:         * last line.
        !          2909:         */
        !          2910:    else if (type == USE_NL)
        !          2911:    {
        !          2912:        windgoto(cursor_end - 1, 0);
        !          2913:        for (i = line_count; --i >= 0; )
        !          2914:            outchar('\n');              /* cursor will remain on same line */
        !          2915:    }
        !          2916:    else
        !          2917:    {
        !          2918:        for (i = line_count; --i >= 0; )
        !          2919:        {
        !          2920:            if (type == USE_T_DL)
        !          2921:            {
        !          2922:                windgoto(cursor_row, 0);
        !          2923:                outstr(T_DL);           /* delete a line */
        !          2924:            }
        !          2925:            else /* type == USE_T_CE */
        !          2926:            {
        !          2927:                windgoto(cursor_row + i, 0);
        !          2928:                outstr(T_CE);           /* erase a line */
        !          2929:            }
        !          2930:            screen_start();             /* don't know where cursor is now */
        !          2931:        }
        !          2932:    }
        !          2933:
        !          2934:    /*
        !          2935:     * If the 'db' flag is set, we need to clear the lines that have been
        !          2936:     * scrolled up at the bottom of the region.
        !          2937:     */
        !          2938:    if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
        !          2939:    {
        !          2940:        for (i = line_count; i > 0; --i)
        !          2941:        {
        !          2942:            windgoto(cursor_end - i, 0);
        !          2943:            outstr(T_CE);               /* erase a line */
        !          2944:            screen_start();             /* don't know where cursor is now */
        !          2945:        }
        !          2946:    }
        !          2947:    return OK;
        !          2948: }
        !          2949:
        !          2950: /*
        !          2951:  * show the current mode and ruler
        !          2952:  *
        !          2953:  * If clear_cmdline is TRUE, clear the rest of the cmdline.
        !          2954:  * If clear_cmdline is FALSE there may be a message there that needs to be
        !          2955:  * cleared only if a mode is shown.
        !          2956:  */
        !          2957:    void
        !          2958: showmode()
        !          2959: {
        !          2960:    int     need_clear = FALSE;
        !          2961:    int     do_mode = (p_smd &&
        !          2962:                         ((State & INSERT) || restart_edit || VIsual_active));
        !          2963:
        !          2964:    if (do_mode || Recording)
        !          2965:    {
        !          2966:        if (emsg_on_display)
        !          2967:        {
        !          2968:            mch_delay(1000L, TRUE);
        !          2969:            emsg_on_display = FALSE;
        !          2970:        }
        !          2971:        msg_didout = FALSE;             /* never scroll up */
        !          2972:        msg_col = 0;
        !          2973:        gotocmdline(FALSE);
        !          2974:        set_highlight('M');     /* Highlight mode */
        !          2975:        if (do_mode)
        !          2976:        {
        !          2977:            start_highlight();
        !          2978:            MSG_OUTSTR("--");
        !          2979: #ifdef INSERT_EXPAND
        !          2980:            if (edit_submode != NULL)       /* CTRL-X in Insert mode */
        !          2981:            {
        !          2982:                msg_outstr(edit_submode);
        !          2983:                if (edit_submode_extra != NULL)
        !          2984:                {
        !          2985:                    msg_outchar(' ');       /* add a space in between */
        !          2986:                    if (edit_submode_highl)
        !          2987:                    {
        !          2988:                        stop_highlight();
        !          2989:                        set_highlight('r');     /* Highlight mode */
        !          2990:                        start_highlight();
        !          2991:                    }
        !          2992:                    msg_outstr(edit_submode_extra);
        !          2993:                    if (edit_submode_highl)
        !          2994:                    {
        !          2995:                        stop_highlight();
        !          2996:                        set_highlight('M');     /* Highlight mode */
        !          2997:                        start_highlight();
        !          2998:                    }
        !          2999:                }
        !          3000:            }
        !          3001:            else
        !          3002: #endif
        !          3003:            {
        !          3004:                if (State == INSERT)
        !          3005:                {
        !          3006: #ifdef RIGHTLEFT
        !          3007:                    if (p_ri)
        !          3008:                        MSG_OUTSTR(" REVERSE");
        !          3009: #endif
        !          3010:                    MSG_OUTSTR(" INSERT");
        !          3011:                }
        !          3012:                else if (State == REPLACE)
        !          3013:                    MSG_OUTSTR(" REPLACE");
        !          3014:                else if (restart_edit == 'I')
        !          3015:                    MSG_OUTSTR(" (insert)");
        !          3016:                else if (restart_edit == 'R')
        !          3017:                    MSG_OUTSTR(" (replace)");
        !          3018: #ifdef RIGHTLEFT
        !          3019:                if (p_hkmap)
        !          3020:                    MSG_OUTSTR(" Hebrew");
        !          3021: #endif
        !          3022:                if ((State & INSERT) && p_paste)
        !          3023:                    MSG_OUTSTR(" (paste)");
        !          3024:                if (VIsual_active)
        !          3025:                {
        !          3026:                    MSG_OUTSTR(" VISUAL");
        !          3027:                    if (VIsual_mode == Ctrl('V'))
        !          3028:                        MSG_OUTSTR(" BLOCK");
        !          3029:                    else if (VIsual_mode == 'V')
        !          3030:                        MSG_OUTSTR(" LINE");
        !          3031:                }
        !          3032:            }
        !          3033:            MSG_OUTSTR(" --");
        !          3034:            need_clear = TRUE;
        !          3035:        }
        !          3036:        if (Recording)
        !          3037:        {
        !          3038:            if (!need_clear)
        !          3039:                start_highlight();
        !          3040:            MSG_OUTSTR("recording");
        !          3041:            need_clear = TRUE;
        !          3042:        }
        !          3043:        if (need_clear)
        !          3044:            stop_highlight();
        !          3045:        if (need_clear || clear_cmdline)
        !          3046:            msg_clr_eos();
        !          3047:        msg_didout = FALSE;             /* overwrite this message */
        !          3048:        msg_col = 0;
        !          3049:    }
        !          3050:    else if (clear_cmdline)             /* just clear anything */
        !          3051:    {
        !          3052:        msg_row = cmdline_row;
        !          3053:        msg_col = 0;
        !          3054:        msg_clr_eos();                  /* will reset clear_cmdline */
        !          3055:    }
        !          3056:    win_redr_ruler(lastwin, TRUE);
        !          3057:    redraw_cmdline = FALSE;
        !          3058: }
        !          3059:
        !          3060: /*
        !          3061:  * delete mode message
        !          3062:  */
        !          3063:    void
        !          3064: delmode()
        !          3065: {
        !          3066:    if (Recording)
        !          3067:        MSG("recording");
        !          3068:    else
        !          3069:        MSG("");
        !          3070: }
        !          3071:
        !          3072: /*
        !          3073:  * if ruler option is set: show current cursor position
        !          3074:  * if always is FALSE, only print if position has changed
        !          3075:  */
        !          3076:    void
        !          3077: showruler(always)
        !          3078:    int     always;
        !          3079: {
        !          3080:    win_redr_ruler(curwin, always);
        !          3081: }
        !          3082:
        !          3083:    void
        !          3084: win_redr_ruler(wp, always)
        !          3085:    WIN     *wp;
        !          3086:    int     always;
        !          3087: {
        !          3088:    static linenr_t old_lnum = 0;
        !          3089:    static colnr_t  old_col = 0;
        !          3090:    char_u          buffer[30];
        !          3091:    int             row;
        !          3092:    int             fillchar;
        !          3093:
        !          3094:    if (p_ru && (redraw_cmdline || always ||
        !          3095:                wp->w_cursor.lnum != old_lnum || wp->w_virtcol != old_col))
        !          3096:    {
        !          3097:        cursor_off();
        !          3098:        if (wp->w_status_height)
        !          3099:        {
        !          3100:            row = wp->w_winpos + wp->w_height;
        !          3101:            if (set_highlight('s') == OK)       /* can use highlighting */
        !          3102:            {
        !          3103:                fillchar = ' ';
        !          3104:                start_highlight();
        !          3105:            }
        !          3106:            else
        !          3107:                fillchar = '=';
        !          3108:        }
        !          3109:        else
        !          3110:        {
        !          3111:            row = Rows - 1;
        !          3112:            fillchar = ' ';
        !          3113:        }
        !          3114:        /*
        !          3115:         * Some sprintfs return the length, some return a pointer.
        !          3116:         * To avoid portability problems we use strlen() here.
        !          3117:         */
        !          3118:
        !          3119:        sprintf((char *)buffer, "%ld,",
        !          3120:                (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ?
        !          3121:                    0L :
        !          3122:                    (long)(wp->w_cursor.lnum));
        !          3123:        /*
        !          3124:         * Check if cursor.lnum is valid, since win_redr_ruler() may be called
        !          3125:         * after deleting lines, before cursor.lnum is corrected.
        !          3126:         */
        !          3127:        if (wp->w_cursor.lnum <= wp->w_buffer->b_ml.ml_line_count)
        !          3128:            col_print(buffer + STRLEN(buffer),
        !          3129:                !(State & INSERT) &&
        !          3130:                *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL ?
        !          3131:                    0 :
        !          3132:                    (int)wp->w_cursor.col + 1,
        !          3133:                    (int)wp->w_virtcol + 1);
        !          3134:
        !          3135:        screen_msg(buffer, row, ru_col);
        !          3136:        screen_fill(row, row + 1, ru_col + (int)STRLEN(buffer),
        !          3137:                                            (int)Columns, fillchar, fillchar);
        !          3138:        old_lnum = wp->w_cursor.lnum;
        !          3139:        old_col = wp->w_virtcol;
        !          3140:        stop_highlight();
        !          3141:    }
        !          3142: }
        !          3143:
        !          3144: /*
        !          3145:  * screen_valid -  allocate screen buffers if size changed
        !          3146:  *   If "clear" is TRUE: clear screen if it has been resized.
        !          3147:  *     Returns TRUE if there is a valid screen to write to.
        !          3148:  *     Returns FALSE when starting up and screen not initialized yet.
        !          3149:  */
        !          3150:    int
        !          3151: screen_valid(clear)
        !          3152:    int     clear;
        !          3153: {
        !          3154:    screenalloc(clear);     /* allocate screen buffers if size changed */
        !          3155:    return (NextScreen != NULL);
        !          3156: }
        !          3157:
        !          3158: #ifdef USE_MOUSE
        !          3159: /*
        !          3160:  * Move the cursor to the specified row and column on the screen.
        !          3161:  * Change current window if neccesary.  Returns an integer with the
        !          3162:  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
        !          3163:  *
        !          3164:  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
        !          3165:  * if the mouse is outside the window then the text will scroll, or if the
        !          3166:  * mouse was previously on a status line, then the status line may be dragged.
        !          3167:  *
        !          3168:  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
        !          3169:  * cursor is moved unless the cursor was on a status line.  Ignoring the
        !          3170:  * CURSOR_MOVED bit, this function returns one of IN_UNKNOWN, IN_BUFFER, or
        !          3171:  * IN_STATUS_LINE depending on where the cursor was clicked.
        !          3172:  *
        !          3173:  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
        !          3174:  * the last call.
        !          3175:  *
        !          3176:  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
        !          3177:  * remembered.
        !          3178:  */
        !          3179:    int
        !          3180: jump_to_mouse(flags)
        !          3181:    int     flags;
        !          3182: {
        !          3183:    static int on_status_line = 0;      /* #lines below bottom of window */
        !          3184:    static int prev_row = -1;
        !          3185:    static int prev_col = -1;
        !          3186:
        !          3187:    WIN     *wp, *old_curwin;
        !          3188:    FPOS    old_cursor;
        !          3189:    int     count;
        !          3190:    int     first;
        !          3191:    int     row = mouse_row;
        !          3192:    int     col = mouse_col;
        !          3193:
        !          3194:    mouse_past_bottom = FALSE;
        !          3195:    mouse_past_eol = FALSE;
        !          3196:
        !          3197:    if ((flags & MOUSE_DID_MOVE) && prev_row == mouse_row &&
        !          3198:                                                        prev_col == mouse_col)
        !          3199:        return IN_BUFFER;               /* mouse pointer didn't move */
        !          3200:
        !          3201:    prev_row = mouse_row;
        !          3202:    prev_col = mouse_col;
        !          3203:
        !          3204:    if ((flags & MOUSE_SETPOS))
        !          3205:        return IN_BUFFER;               /* mouse pointer didn't move */
        !          3206:
        !          3207:    old_curwin = curwin;
        !          3208:    old_cursor = curwin->w_cursor;
        !          3209:
        !          3210:    if (!(flags & MOUSE_FOCUS))
        !          3211:    {
        !          3212:        if (row < 0 || col < 0)     /* check if it makes sense */
        !          3213:            return IN_UNKNOWN;
        !          3214:
        !          3215:        /* find the window where the row is in */
        !          3216:        for (wp = firstwin; wp->w_next; wp = wp->w_next)
        !          3217:            if (row < wp->w_next->w_winpos)
        !          3218:                break;
        !          3219:        /*
        !          3220:         * winpos and height may change in win_enter()!
        !          3221:         */
        !          3222:        row -= wp->w_winpos;
        !          3223:        if (row >= wp->w_height)    /* In (or below) status line */
        !          3224:            on_status_line = row - wp->w_height + 1;
        !          3225:        else
        !          3226:            on_status_line = 0;
        !          3227:        win_enter(wp, TRUE);
        !          3228:        if (on_status_line)         /* In (or below) status line */
        !          3229:        {
        !          3230:            /* Don't use start_arrow() if we're in the same window */
        !          3231:            if (curwin == old_curwin)
        !          3232:                return IN_STATUS_LINE;
        !          3233:            else
        !          3234:                return IN_STATUS_LINE | CURSOR_MOVED;
        !          3235:        }
        !          3236:
        !          3237:        curwin->w_cursor.lnum = curwin->w_topline;
        !          3238:    }
        !          3239:    else if (on_status_line)
        !          3240:    {
        !          3241:        /* Drag the status line */
        !          3242:        count = row - curwin->w_winpos - curwin->w_height + 1 - on_status_line;
        !          3243:        win_drag_status_line(count);
        !          3244:        return IN_STATUS_LINE;      /* Cursor didn't move */
        !          3245:    }
        !          3246:    else /* keep_window_focus must be TRUE */
        !          3247:    {
        !          3248:        row -= curwin->w_winpos;
        !          3249:
        !          3250:        /*
        !          3251:         * When clicking beyond the end of the window, scroll the screen.
        !          3252:         * Scroll by however many rows outside the window we are.
        !          3253:         */
        !          3254:        if (row < 0)
        !          3255:        {
        !          3256:            count = 0;
        !          3257:            for (first = TRUE; curwin->w_topline > 1; --curwin->w_topline)
        !          3258:            {
        !          3259:                count += plines(curwin->w_topline - 1);
        !          3260:                if (!first && count > -row)
        !          3261:                    break;
        !          3262:                first = FALSE;
        !          3263:            }
        !          3264:            redraw_later(VALID);
        !          3265:            row = 0;
        !          3266:        }
        !          3267:        else if (row >= curwin->w_height)
        !          3268:        {
        !          3269:            count = 0;
        !          3270:            for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count;
        !          3271:                                                        ++curwin->w_topline)
        !          3272:            {
        !          3273:                count += plines(curwin->w_topline);
        !          3274:                if (!first && count > row - curwin->w_height + 1)
        !          3275:                    break;
        !          3276:                first = FALSE;
        !          3277:            }
        !          3278:            redraw_later(VALID);
        !          3279:            row = curwin->w_height - 1;
        !          3280:        }
        !          3281:        curwin->w_cursor.lnum = curwin->w_topline;
        !          3282:    }
        !          3283:
        !          3284: #ifdef RIGHTLEFT
        !          3285:    if (curwin->w_p_rl)
        !          3286:        col = Columns - 1 - col;
        !          3287: #endif
        !          3288:
        !          3289:    if (curwin->w_p_nu)         /* skip number in front of the line */
        !          3290:        if ((col -= 8) < 0)
        !          3291:            col = 0;
        !          3292:
        !          3293:    if (curwin->w_p_wrap)       /* lines wrap */
        !          3294:    {
        !          3295:        while (row)
        !          3296:        {
        !          3297:            count = plines(curwin->w_cursor.lnum);
        !          3298:            if (count > row)
        !          3299:            {
        !          3300:                col += row * Columns;
        !          3301:                break;
        !          3302:            }
        !          3303:            if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
        !          3304:            {
        !          3305:                mouse_past_bottom = TRUE;
        !          3306:                break;
        !          3307:            }
        !          3308:            row -= count;
        !          3309:            ++curwin->w_cursor.lnum;
        !          3310:        }
        !          3311:    }
        !          3312:    else                        /* lines don't wrap */
        !          3313:    {
        !          3314:        curwin->w_cursor.lnum += row;
        !          3315:        if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
        !          3316:        {
        !          3317:            curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
        !          3318:            mouse_past_bottom = TRUE;
        !          3319:        }
        !          3320:        col += curwin->w_leftcol;
        !          3321:    }
        !          3322:    curwin->w_curswant = col;
        !          3323:    curwin->w_set_curswant = FALSE;     /* May still have been TRUE */
        !          3324:    if (coladvance(col) == FAIL)
        !          3325:    {
        !          3326:        /* Mouse click beyond end of line */
        !          3327:        op_inclusive = TRUE;
        !          3328:        mouse_past_eol = TRUE;
        !          3329:    }
        !          3330:    else
        !          3331:        op_inclusive = FALSE;
        !          3332:
        !          3333:    if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
        !          3334:    {
        !          3335:        start_visual_highlight();
        !          3336:        VIsual = old_cursor;
        !          3337:        VIsual_active = TRUE;
        !          3338: #ifdef USE_MOUSE
        !          3339:        setmouse();
        !          3340: #endif
        !          3341:        if (p_smd)
        !          3342:            redraw_cmdline = TRUE;          /* show visual mode later */
        !          3343:    }
        !          3344:
        !          3345:    if (curwin == old_curwin && curwin->w_cursor.lnum == old_cursor.lnum &&
        !          3346:                                       curwin->w_cursor.col == old_cursor.col)
        !          3347:        return IN_BUFFER;               /* Cursor has not moved */
        !          3348:    return IN_BUFFER | CURSOR_MOVED;    /* Cursor has moved */
        !          3349: }
        !          3350: #endif /* USE_MOUSE */
        !          3351:
        !          3352: /*
        !          3353:  * Redraw the screen later, with UpdateScreen(type).
        !          3354:  * Set must_redraw only of not already set to a higher value.
        !          3355:  * e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
        !          3356:  */
        !          3357:    void
        !          3358: redraw_later(type)
        !          3359:    int     type;
        !          3360: {
        !          3361:    if (must_redraw < type)
        !          3362:        must_redraw = type;
        !          3363: }