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

Annotation of src/usr.bin/vim/window.c, Revision 1.1.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 a list of people who contributed.
                      7:  * Do ":help credits" in Vim to see a list of people who contributed.
                      8:  */
                      9:
                     10: #include "vim.h"
                     11: #include "globals.h"
                     12: #include "proto.h"
                     13: #include "option.h"
                     14:
                     15: static void reset_VIsual __ARGS((void));
                     16: static int win_comp_pos __ARGS((void));
                     17: static void win_exchange __ARGS((long));
                     18: static void win_rotate __ARGS((int, int));
                     19: static void win_append __ARGS((WIN *, WIN *));
                     20: static void win_remove __ARGS((WIN *));
                     21: static void win_new_height __ARGS((WIN *, int));
                     22:
                     23: static WIN     *prevwin = NULL;        /* previous window */
                     24:
                     25: /*
                     26:  * all CTRL-W window commands are handled here, called from normal().
                     27:  */
                     28:    void
                     29: do_window(nchar, Prenum)
                     30:    int     nchar;
                     31:    long    Prenum;
                     32: {
                     33:    long    Prenum1;
                     34:    WIN     *wp;
                     35:    char_u  *ptr;
                     36:    int     len;
                     37:    int     type = -1;
                     38:    WIN     *wp2;
                     39:
                     40:    if (Prenum == 0)
                     41:        Prenum1 = 1;
                     42:    else
                     43:        Prenum1 = Prenum;
                     44:
                     45:    switch (nchar)
                     46:    {
                     47: /* split current window in two parts */
                     48:    case 'S':
                     49:    case Ctrl('S'):
                     50:    case 's':   reset_VIsual();                 /* stop Visual mode */
                     51:                win_split((int)Prenum, TRUE);
                     52:                break;
                     53:
                     54: /* split current window and edit alternate file */
                     55:    case K_CCIRCM:
                     56:    case '^':
                     57:                reset_VIsual();                 /* stop Visual mode */
                     58:                stuffReadbuff((char_u *)":split #");
                     59:                if (Prenum)
                     60:                    stuffnumReadbuff(Prenum);   /* buffer number */
                     61:                stuffcharReadbuff('\n');
                     62:                break;
                     63:
                     64: /* open new window */
                     65:    case Ctrl('N'):
                     66:    case 'n':   reset_VIsual();                 /* stop Visual mode */
                     67:                stuffcharReadbuff(':');
                     68:                if (Prenum)
                     69:                    stuffnumReadbuff(Prenum);       /* window height */
                     70:                stuffReadbuff((char_u *)"new\n");   /* it is cmdline.c */
                     71:                break;
                     72:
                     73: /* quit current window */
                     74:    case Ctrl('Q'):
                     75:    case 'q':   reset_VIsual();                 /* stop Visual mode */
                     76:                stuffReadbuff((char_u *)":quit\n"); /* it is cmdline.c */
                     77:                break;
                     78:
                     79: /* close current window */
                     80:    case Ctrl('C'):
                     81:    case 'c':   reset_VIsual();                 /* stop Visual mode */
                     82:                stuffReadbuff((char_u *)":close\n");    /* it is cmdline.c */
                     83:                break;
                     84:
                     85: /* close all but current window */
                     86:    case Ctrl('O'):
                     87:    case 'o':   reset_VIsual();                 /* stop Visual mode */
                     88:                stuffReadbuff((char_u *)":only\n"); /* it is cmdline.c */
                     89:                break;
                     90:
                     91: /* cursor to next window */
                     92:    case 'j':
                     93:    case K_DOWN:
                     94:    case Ctrl('J'):
                     95:                for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
                     96:                                                            wp = wp->w_next)
                     97:                    ;
                     98: new_win:
                     99:                /*
                    100:                 * When jumping to another buffer, stop visual mode
                    101:                 * Do this before changing windows so we can yank the
                    102:                 * selection into the '"*' register.
                    103:                 */
                    104:                if (wp->w_buffer != curbuf && VIsual_active)
                    105:                {
                    106:                    end_visual_mode();
                    107:                    for (wp2 = firstwin; wp2 != NULL; wp2 = wp2->w_next)
                    108:                        if (wp2->w_buffer == curbuf &&
                    109:                                            wp2->w_redr_type < NOT_VALID)
                    110:                        {
                    111:                            wp2->w_redr_type = NOT_VALID;
                    112:                            redraw_later(NOT_VALID);
                    113:                        }
                    114:                }
                    115:                win_enter(wp, TRUE);
                    116:                cursupdate();
                    117:                break;
                    118:
                    119: /* cursor to next window with wrap around */
                    120:    case Ctrl('W'):
                    121:    case 'w':
                    122: /* cursor to previous window with wrap around */
                    123:    case 'W':
                    124:                if (lastwin == firstwin)        /* just one window */
                    125:                    beep_flush();
                    126:                else
                    127:                {
                    128:                    if (Prenum)                 /* go to specified window */
                    129:                    {
                    130:                        for (wp = firstwin; --Prenum > 0; )
                    131:                        {
                    132:                            if (wp->w_next == NULL)
                    133:                                break;
                    134:                            else
                    135:                                wp = wp->w_next;
                    136:                        }
                    137:                    }
                    138:                    else
                    139:                    {
                    140:                        if (nchar == 'W')           /* go to previous window */
                    141:                        {
                    142:                            wp = curwin->w_prev;
                    143:                            if (wp == NULL)
                    144:                                wp = lastwin;       /* wrap around */
                    145:                        }
                    146:                        else                        /* go to next window */
                    147:                        {
                    148:                            wp = curwin->w_next;
                    149:                            if (wp == NULL)
                    150:                                wp = firstwin;      /* wrap around */
                    151:                        }
                    152:                    }
                    153:                    goto new_win;
                    154:                }
                    155:                break;
                    156:
                    157: /* cursor to window above */
                    158:    case 'k':
                    159:    case K_UP:
                    160:    case Ctrl('K'):
                    161:                for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
                    162:                                                            wp = wp->w_prev)
                    163:                    ;
                    164:                goto new_win;
                    165:
                    166: /* cursor to top window */
                    167:    case 't':
                    168:    case Ctrl('T'):
                    169:                wp = firstwin;
                    170:                goto new_win;
                    171:
                    172: /* cursor to bottom window */
                    173:    case 'b':
                    174:    case Ctrl('B'):
                    175:                wp = lastwin;
                    176:                goto new_win;
                    177:
                    178: /* cursor to last accessed (previous) window */
                    179:    case 'p':
                    180:    case Ctrl('P'):
                    181:                if (prevwin == NULL)
                    182:                    beep_flush();
                    183:                else
                    184:                {
                    185:                    wp = prevwin;
                    186:                    goto new_win;
                    187:                }
                    188:                break;
                    189:
                    190: /* exchange current and next window */
                    191:    case 'x':
                    192:    case Ctrl('X'):
                    193:                win_exchange(Prenum);
                    194:                break;
                    195:
                    196: /* rotate windows downwards */
                    197:    case Ctrl('R'):
                    198:    case 'r':   reset_VIsual();                 /* stop Visual mode */
                    199:                win_rotate(FALSE, (int)Prenum1);    /* downwards */
                    200:                break;
                    201:
                    202: /* rotate windows upwards */
                    203:    case 'R':   reset_VIsual();                 /* stop Visual mode */
                    204:                win_rotate(TRUE, (int)Prenum1);     /* upwards */
                    205:                break;
                    206:
                    207: /* make all windows the same height */
                    208:    case '=':   win_equal(NULL, TRUE);
                    209:                break;
                    210:
                    211: /* increase current window height */
                    212:    case '+':   win_setheight(curwin->w_height + (int)Prenum1);
                    213:                break;
                    214:
                    215: /* decrease current window height */
                    216:    case '-':   win_setheight(curwin->w_height - (int)Prenum1);
                    217:                break;
                    218:
                    219: /* set current window height */
                    220:    case Ctrl('_'):
                    221:    case '_':   win_setheight(Prenum ? (int)Prenum : 9999);
                    222:                break;
                    223:
                    224: /* jump to tag and split window if tag exists */
                    225:    case ']':
                    226:    case Ctrl(']'):
                    227:                reset_VIsual();                 /* stop Visual mode */
                    228:                postponed_split = TRUE;
                    229:                stuffcharReadbuff(Ctrl(']'));
                    230:                break;
                    231:
                    232: /* edit file name under cursor in a new window */
                    233:    case 'f':
                    234:    case Ctrl('F'):
                    235:                reset_VIsual();                 /* stop Visual mode */
                    236:                ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP);
                    237:                if (ptr != NULL)
                    238:                {
                    239:                    setpcmark();
                    240:                    if (win_split(0, FALSE) == OK)
                    241:                        (void)do_ecmd(0, ptr, NULL, NULL, p_hid, (linenr_t)0, FALSE);
                    242:                    vim_free(ptr);
                    243:                }
                    244:                break;
                    245:
                    246: /* Go to the first occurence of the identifier under cursor along path in a
                    247:  * new window -- webb
                    248:  */
                    249:    case 'i':                       /* Go to any match */
                    250:    case Ctrl('I'):
                    251:                type = FIND_ANY;
                    252:                /* FALLTHROUGH */
                    253:    case 'd':                       /* Go to definition, using p_def */
                    254:    case Ctrl('D'):
                    255:                if (type == -1)
                    256:                    type = FIND_DEFINE;
                    257:
                    258:                if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
                    259:                    break;
                    260:                find_pattern_in_path(ptr, len, TRUE, TRUE, type,
                    261:                       Prenum1, ACTION_SPLIT, (linenr_t)1, (linenr_t)MAXLNUM);
                    262:                curwin->w_set_curswant = TRUE;
                    263:                break;
                    264:
                    265:    default:    beep_flush();
                    266:                break;
                    267:    }
                    268: }
                    269:
                    270:    static void
                    271: reset_VIsual()
                    272: {
                    273:    if (VIsual_active)
                    274:    {
                    275:        end_visual_mode();
                    276:        update_curbuf(NOT_VALID);       /* delete the inversion */
                    277:    }
                    278: }
                    279:
                    280: /*
                    281:  * split the current window, implements CTRL-W s and :split
                    282:  *
                    283:  * new_height is the height for the new window, 0 to make half of current
                    284:  * height redraw is TRUE when redraw now
                    285:  *
                    286:  * return FAIL for failure, OK otherwise
                    287:  */
                    288:    int
                    289: win_split(new_height, redraw)
                    290:    int     new_height;
                    291:    int     redraw;
                    292: {
                    293:    WIN         *wp;
                    294:    linenr_t    lnum;
                    295:    int         h;
                    296:    int         i;
                    297:    int         need_status;
                    298:    int         do_equal = (p_ea && new_height == 0);
                    299:    int         needed;
                    300:    int         available;
                    301:    int         curwin_height;
                    302:
                    303:        /* add a status line when p_ls == 1 and splitting the first window */
                    304:    if (lastwin == firstwin && p_ls == 1 && curwin->w_status_height == 0)
                    305:        need_status = STATUS_HEIGHT;
                    306:    else
                    307:        need_status = 0;
                    308:
                    309: /*
                    310:  * check if we are able to split the current window and compute its height
                    311:  */
                    312:    available = curwin->w_height;
                    313:    needed = 2 * MIN_ROWS + STATUS_HEIGHT + need_status;
                    314:    if (p_ea)
                    315:    {
                    316:        for (wp = firstwin; wp != NULL; wp = wp->w_next)
                    317:            if (wp != curwin)
                    318:            {
                    319:                available += wp->w_height;
                    320:                needed += MIN_ROWS;
                    321:            }
                    322:    }
                    323:    if (available < needed)
                    324:    {
                    325:        EMSG(e_noroom);
                    326:        return FAIL;
                    327:    }
                    328:    curwin_height = curwin->w_height;
                    329:    if (need_status)
                    330:    {
                    331:        curwin->w_status_height = STATUS_HEIGHT;
                    332:        curwin_height -= STATUS_HEIGHT;
                    333:    }
                    334:    if (new_height == 0)
                    335:        new_height = curwin_height / 2;
                    336:
                    337:    if (new_height > curwin_height - MIN_ROWS - STATUS_HEIGHT)
                    338:        new_height = curwin_height - MIN_ROWS - STATUS_HEIGHT;
                    339:
                    340:    if (new_height < MIN_ROWS)
                    341:        new_height = MIN_ROWS;
                    342:
                    343:        /* if it doesn't fit in the current window, need win_equal() */
                    344:    if (curwin_height - new_height - STATUS_HEIGHT < MIN_ROWS)
                    345:        do_equal = TRUE;
                    346: /*
                    347:  * allocate new window structure and link it in the window list
                    348:  */
                    349:    if (p_sb)       /* new window below current one */
                    350:        wp = win_alloc(curwin);
                    351:    else
                    352:        wp = win_alloc(curwin->w_prev);
                    353:    if (wp == NULL)
                    354:        return FAIL;
                    355: /*
                    356:  * compute the new screen positions
                    357:  */
                    358:    win_new_height(wp, new_height);
                    359:    win_new_height(curwin, curwin_height - (new_height + STATUS_HEIGHT));
                    360:    if (p_sb)       /* new window below current one */
                    361:    {
                    362:        wp->w_winpos = curwin->w_winpos + curwin->w_height + STATUS_HEIGHT;
                    363:        wp->w_status_height = curwin->w_status_height;
                    364:        curwin->w_status_height = STATUS_HEIGHT;
                    365:    }
                    366:    else            /* new window above current one */
                    367:    {
                    368:        wp->w_winpos = curwin->w_winpos;
                    369:        wp->w_status_height = STATUS_HEIGHT;
                    370:        curwin->w_winpos = wp->w_winpos + wp->w_height + STATUS_HEIGHT;
                    371:    }
                    372: /*
                    373:  * make the contents of the new window the same as the current one
                    374:  */
                    375:    wp->w_buffer = curbuf;
                    376:    curbuf->b_nwindows++;
                    377:    wp->w_cursor = curwin->w_cursor;
                    378:    wp->w_row = curwin->w_row;
                    379:    wp->w_col = curwin->w_col;
                    380:    wp->w_virtcol = curwin->w_virtcol;
                    381:    wp->w_curswant = curwin->w_curswant;
                    382:    wp->w_set_curswant = curwin->w_set_curswant;
                    383:    wp->w_empty_rows = curwin->w_empty_rows;
                    384:    wp->w_leftcol = curwin->w_leftcol;
                    385:    wp->w_pcmark = curwin->w_pcmark;
                    386:    wp->w_prev_pcmark = curwin->w_prev_pcmark;
                    387:    wp->w_alt_fnum = curwin->w_alt_fnum;
                    388:
                    389:    wp->w_arg_idx = curwin->w_arg_idx;
                    390:    /*
                    391:     * copy tagstack and options from existing window
                    392:     */
                    393:    for (i = 0; i < curwin->w_tagstacklen; i++)
                    394:    {
                    395:        wp->w_tagstack[i].fmark = curwin->w_tagstack[i].fmark;
                    396:        wp->w_tagstack[i].tagname = strsave(curwin->w_tagstack[i].tagname);
                    397:    }
                    398:    wp->w_tagstackidx = curwin->w_tagstackidx;
                    399:    wp->w_tagstacklen = curwin->w_tagstacklen;
                    400:    win_copy_options(curwin, wp);
                    401: /*
                    402:  * Both windows need redrawing
                    403:  */
                    404:    wp->w_redr_type = NOT_VALID;
                    405:    wp->w_redr_status = TRUE;
                    406:    curwin->w_redr_type = NOT_VALID;
                    407:    curwin->w_redr_status = TRUE;
                    408: /*
                    409:  * Cursor is put in middle of window in both windows
                    410:  */
                    411:    if (wp->w_height < curwin->w_height)    /* use smallest of two heights */
                    412:        h = wp->w_height;
                    413:    else
                    414:        h = curwin->w_height;
                    415:    h >>= 1;
                    416:    for (lnum = wp->w_cursor.lnum; lnum > 1; --lnum)
                    417:    {
                    418:        h -= plines(lnum);
                    419:        if (h <= 0)
                    420:            break;
                    421:    }
                    422:    wp->w_topline = lnum;
                    423:    curwin->w_topline = lnum;
                    424:    if (need_status)
                    425:    {
                    426:        msg_pos((int)Rows - 1, sc_col);
                    427:        msg_clr_eos();      /* Old command/ruler may still be there -- webb */
                    428:        comp_col();
                    429:        msg_pos((int)Rows - 1, 0);  /* put position back at start of line */
                    430:    }
                    431: /*
                    432:  * make the new window the current window and redraw
                    433:  */
                    434:    if (do_equal)
                    435:        win_equal(wp, FALSE);
                    436:    win_enter(wp, FALSE);
                    437:
                    438:    if (redraw)
                    439:        updateScreen(NOT_VALID);
                    440:
                    441:    return OK;
                    442: }
                    443:
                    444: /*
                    445:  * Return the number of windows.
                    446:  */
                    447:    int
                    448: win_count()
                    449: {
                    450:    WIN     *wp;
                    451:    int     count = 0;
                    452:
                    453:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                    454:        ++count;
                    455:    return count;
                    456: }
                    457:
                    458: /*
                    459:  * Make 'count' windows on the screen.
                    460:  * Return actual number of windows on the screen.
                    461:  * Must be called when there is just one window, filling the whole screen
                    462:  * (excluding the command line).
                    463:  */
                    464:    int
                    465: make_windows(count)
                    466:    int     count;
                    467: {
                    468:    int     maxcount;
                    469:    int     todo;
                    470:    int     p_sb_save;
                    471:
                    472: /*
                    473:  * Each window needs at least MIN_ROWS lines and a status line.
                    474:  * Add 4 lines for one window, otherwise we may end up with all one-line
                    475:  * windows. Use value of 'winheight' if it is set
                    476:  */
                    477:    maxcount = (curwin->w_height + curwin->w_status_height -
                    478:                        (p_wh ? (p_wh - 1) : 4)) / (MIN_ROWS + STATUS_HEIGHT);
                    479:    if (maxcount < 2)
                    480:        maxcount = 2;
                    481:    if (count > maxcount)
                    482:        count = maxcount;
                    483:
                    484:    /*
                    485:     * add status line now, otherwise first window will be too big
                    486:     */
                    487:    if ((p_ls == 2 || (count > 1 && p_ls == 1)) && curwin->w_status_height == 0)
                    488:    {
                    489:        curwin->w_status_height = STATUS_HEIGHT;
                    490:        win_new_height(curwin, curwin->w_height - STATUS_HEIGHT);
                    491:    }
                    492:
                    493: /*
                    494:  * set 'splitbelow' off for a moment, don't want that now
                    495:  */
                    496:    p_sb_save = p_sb;
                    497:    p_sb = FALSE;
                    498:        /* todo is number of windows left to create */
                    499:    for (todo = count - 1; todo > 0; --todo)
                    500:        if (win_split(curwin->w_height - (curwin->w_height - todo
                    501:                * STATUS_HEIGHT) / (todo + 1) - STATUS_HEIGHT, FALSE) == FAIL)
                    502:            break;
                    503:    p_sb = p_sb_save;
                    504:
                    505:        /* return actual number of windows */
                    506:    return (count - todo);
                    507: }
                    508:
                    509: /*
                    510:  * Exchange current and next window
                    511:  */
                    512:    static void
                    513: win_exchange(Prenum)
                    514:    long        Prenum;
                    515: {
                    516:    WIN     *wp;
                    517:    WIN     *wp2;
                    518:    int     temp;
                    519:
                    520:    if (lastwin == firstwin)        /* just one window */
                    521:    {
                    522:        beep_flush();
                    523:        return;
                    524:    }
                    525:
                    526: /*
                    527:  * find window to exchange with
                    528:  */
                    529:    if (Prenum)
                    530:    {
                    531:        wp = firstwin;
                    532:        while (wp != NULL && --Prenum > 0)
                    533:            wp = wp->w_next;
                    534:    }
                    535:    else if (curwin->w_next != NULL)    /* Swap with next */
                    536:        wp = curwin->w_next;
                    537:    else    /* Swap last window with previous */
                    538:        wp = curwin->w_prev;
                    539:
                    540:    if (wp == curwin || wp == NULL)
                    541:        return;
                    542:
                    543: /*
                    544:  * 1. remove curwin from the list. Remember after which window it was in wp2
                    545:  * 2. insert curwin before wp in the list
                    546:  * if wp != wp2
                    547:  *    3. remove wp from the list
                    548:  *    4. insert wp after wp2
                    549:  * 5. exchange the status line height
                    550:  */
                    551:    wp2 = curwin->w_prev;
                    552:    win_remove(curwin);
                    553:    win_append(wp->w_prev, curwin);
                    554:    if (wp != wp2)
                    555:    {
                    556:        win_remove(wp);
                    557:        win_append(wp2, wp);
                    558:    }
                    559:    temp = curwin->w_status_height;
                    560:    curwin->w_status_height = wp->w_status_height;
                    561:    wp->w_status_height = temp;
                    562:
                    563:    win_comp_pos();             /* recompute window positions */
                    564:
                    565:    win_enter(wp, TRUE);
                    566:    cursupdate();
                    567:    updateScreen(CLEAR);
                    568:
                    569: #ifdef USE_GUI
                    570:    if (gui.in_use)
                    571:    {
                    572:        if (gui.which_scrollbars[SB_LEFT])
                    573:            gui_mch_reorder_scrollbars(SB_LEFT);
                    574:        if (gui.which_scrollbars[SB_RIGHT])
                    575:            gui_mch_reorder_scrollbars(SB_RIGHT);
                    576:    }
                    577: #endif
                    578: }
                    579:
                    580: /*
                    581:  * rotate windows: if upwards TRUE the second window becomes the first one
                    582:  *                if upwards FALSE the first window becomes the second one
                    583:  */
                    584:    static void
                    585: win_rotate(upwards, count)
                    586:    int     upwards;
                    587:    int     count;
                    588: {
                    589:    WIN          *wp;
                    590:    int          height;
                    591:
                    592:    if (firstwin == lastwin)            /* nothing to do */
                    593:    {
                    594:        beep_flush();
                    595:        return;
                    596:    }
                    597:    while (count--)
                    598:    {
                    599:        if (upwards)            /* first window becomes last window */
                    600:        {
                    601:            wp = firstwin;
                    602:            win_remove(wp);
                    603:            win_append(lastwin, wp);
                    604:            wp = lastwin->w_prev;           /* previously last window */
                    605:        }
                    606:        else                    /* last window becomes first window */
                    607:        {
                    608:            wp = lastwin;
                    609:            win_remove(lastwin);
                    610:            win_append(NULL, wp);
                    611:            wp = firstwin;                  /* previously last window */
                    612:        }
                    613:            /* exchange status height of old and new last window */
                    614:        height = lastwin->w_status_height;
                    615:        lastwin->w_status_height = wp->w_status_height;
                    616:        wp->w_status_height = height;
                    617:
                    618:            /* recompute w_winpos for all windows */
                    619:        (void) win_comp_pos();
                    620:    }
                    621:
                    622:    cursupdate();
                    623:    updateScreen(CLEAR);
                    624:
                    625: #ifdef USE_GUI
                    626:    if (gui.in_use)
                    627:    {
                    628:        if (gui.which_scrollbars[SB_LEFT])
                    629:            gui_mch_reorder_scrollbars(SB_LEFT);
                    630:        if (gui.which_scrollbars[SB_RIGHT])
                    631:            gui_mch_reorder_scrollbars(SB_RIGHT);
                    632:    }
                    633: #endif
                    634: }
                    635:
                    636: /*
                    637:  * Make all windows the same height.
                    638:  * 'next_curwin' will soon be the current window, make sure it has enough
                    639:  * rows.
                    640:  */
                    641:    void
                    642: win_equal(next_curwin, redraw)
                    643:    WIN     *next_curwin;           /* pointer to current window to be */
                    644:    int     redraw;
                    645: {
                    646:    int     total;
                    647:    int     less;
                    648:    int     wincount;
                    649:    int     winpos;
                    650:    int     temp;
                    651:    WIN     *wp;
                    652:    int     new_height;
                    653:
                    654: /*
                    655:  * count the number of lines available
                    656:  */
                    657:    total = 0;
                    658:    wincount = 0;
                    659:    for (wp = firstwin; wp; wp = wp->w_next)
                    660:    {
                    661:        total += wp->w_height - MIN_ROWS;
                    662:        wincount++;
                    663:    }
                    664:
                    665: /*
                    666:  * If next_curwin given and 'winheight' set, make next_curwin p_wh lines.
                    667:  */
                    668:    less = 0;
                    669:    if (next_curwin != NULL)
                    670:    {
                    671:        if (p_wh)
                    672:        {
                    673:            if (p_wh - MIN_ROWS > total)    /* all lines go to current window */
                    674:                less = total;
                    675:            else
                    676:            {
                    677:                less = p_wh - MIN_ROWS - total / wincount;
                    678:                if (less < 0)
                    679:                    less = 0;
                    680:            }
                    681:        }
                    682:    }
                    683:
                    684: /*
                    685:  * spread the available lines over the windows
                    686:  */
                    687:    winpos = 0;
                    688:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                    689:    {
                    690:        if (wp == next_curwin && less)
                    691:        {
                    692:            less = 0;
                    693:            temp = p_wh - MIN_ROWS;
                    694:            if (temp > total)
                    695:                temp = total;
                    696:        }
                    697:        else
                    698:            temp = (total - less + (wincount >> 1)) / wincount;
                    699:        new_height = MIN_ROWS + temp;
                    700:        if (wp->w_winpos != winpos || wp->w_height != new_height)
                    701:        {
                    702:            wp->w_redr_type = NOT_VALID;
                    703:            wp->w_redr_status = TRUE;
                    704:        }
                    705:        wp->w_winpos = winpos;
                    706:        win_new_height(wp, new_height);
                    707:        total -= temp;
                    708:        --wincount;
                    709:        winpos += wp->w_height + wp->w_status_height;
                    710:    }
                    711:    if (redraw)
                    712:    {
                    713:        cursupdate();
                    714:        updateScreen(CLEAR);
                    715:    }
                    716: }
                    717:
                    718: /*
                    719:  * close all windows for buffer 'buf'
                    720:  */
                    721:    void
                    722: close_windows(buf)
                    723:    BUF     *buf;
                    724: {
                    725:    WIN     *win;
                    726:
                    727:    ++RedrawingDisabled;
                    728:    for (win = firstwin; win != NULL && lastwin != firstwin; )
                    729:    {
                    730:        if (win->w_buffer == buf)
                    731:        {
                    732:            close_window(win, FALSE);
                    733:            win = firstwin;         /* go back to the start */
                    734:        }
                    735:        else
                    736:            win = win->w_next;
                    737:    }
                    738:    --RedrawingDisabled;
                    739: }
                    740:
                    741: /*
                    742:  * close window "win"
                    743:  * If "free_buf" is TRUE related buffer may be freed.
                    744:  *
                    745:  * called by :quit, :close, :xit, :wq and findtag()
                    746:  */
                    747:    void
                    748: close_window(win, free_buf)
                    749:    WIN     *win;
                    750:    int     free_buf;
                    751: {
                    752:    WIN     *wp;
                    753:
                    754:    if (lastwin == firstwin)
                    755:    {
                    756:        EMSG("Cannot close last window");
                    757:        return;
                    758:    }
                    759:
                    760: /*
                    761:  * Remove the window.
                    762:  * if 'splitbelow' the free space goes to the window above it.
                    763:  * if 'nosplitbelow' the free space goes to the window below it.
                    764:  * This makes opening a window and closing it immediately keep the same window
                    765:  * layout.
                    766:  */
                    767:                                    /* freed space goes to next window */
                    768:    if ((!p_sb && win->w_next != NULL) || win->w_prev == NULL)
                    769:    {
                    770:        wp = win->w_next;
                    771:        wp->w_winpos = win->w_winpos;
                    772:    }
                    773:    else                            /* freed space goes to previous window */
                    774:        wp = win->w_prev;
                    775:    win_new_height(wp, wp->w_height + win->w_height + win->w_status_height);
                    776:
                    777: #ifdef AUTOCMD
                    778:    if (win == curwin)
                    779:    {
                    780:        if (wp->w_buffer != curbuf)
                    781:            apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
                    782:        apply_autocmds(EVENT_WINLEAVE, NULL, NULL);
                    783:    }
                    784: #endif
                    785:
                    786: /*
                    787:  * Close the link to the buffer.
                    788:  */
                    789:    close_buffer(win, win->w_buffer, free_buf, FALSE);
                    790:
                    791:    win_free(win);
                    792:    if (win == curwin)
                    793:        curwin = NULL;
                    794:    if (p_ea)
                    795:        win_equal(wp, FALSE);
                    796:    if (curwin == NULL)
                    797:        win_enter(wp, FALSE);
                    798:    /*
                    799:     * if last window has status line now and we don't want one,
                    800:     * remove the status line
                    801:     */
                    802:    if (lastwin->w_status_height &&
                    803:                        (p_ls == 0 || (p_ls == 1 && firstwin == lastwin)))
                    804:    {
                    805:        win_new_height(lastwin, lastwin->w_height + lastwin->w_status_height);
                    806:        lastwin->w_status_height = 0;
                    807:        comp_col();
                    808:    }
                    809:
                    810:    updateScreen(NOT_VALID);
                    811:    if (RedrawingDisabled)
                    812:        comp_Botline(wp);           /* need to do this before cursupdate() */
                    813: }
                    814:
                    815: /*
                    816:  * close all windows except current one
                    817:  * buffers in the windows become hidden
                    818:  *
                    819:  * called by :only and do_arg_all();
                    820:  */
                    821:    void
                    822: close_others(message)
                    823:    int     message;
                    824: {
                    825:    WIN     *wp;
                    826:    WIN     *nextwp;
                    827:
                    828:    if (lastwin == firstwin)
                    829:    {
                    830:        if (message
                    831: #ifdef AUTOCMD
                    832:                    && !autocmd_busy
                    833: #endif
                    834:                                    )
                    835:            MSG("Already only one window");
                    836:        return;
                    837:    }
                    838:
                    839:    for (wp = firstwin; wp != NULL; wp = nextwp)
                    840:    {
                    841:        nextwp = wp->w_next;
                    842:        if (wp == curwin)               /* don't close current window */
                    843:            continue;
                    844:        /*
                    845:         * Close the link to the buffer.
                    846:         */
                    847:        close_buffer(wp, wp->w_buffer, FALSE, FALSE);
                    848:
                    849:        /*
                    850:         * Remove the window. All lines go to current window.
                    851:         */
                    852:        win_new_height(curwin,
                    853:                       curwin->w_height + wp->w_height + wp->w_status_height);
                    854:        win_free(wp);
                    855:    }
                    856:
                    857:    /*
                    858:     * If current window has status line and we don't want one,
                    859:     * remove the status line.
                    860:     */
                    861:    if (curwin->w_status_height && p_ls != 2)
                    862:    {
                    863:        win_new_height(curwin, curwin->w_height + curwin->w_status_height);
                    864:        curwin->w_status_height = 0;
                    865:    }
                    866:    curwin->w_winpos = 0;       /* put current window at top of the screen */
                    867:    if (message)
                    868:        updateScreen(NOT_VALID);
                    869: }
                    870:
                    871: /*
                    872:  * init the cursor in the window
                    873:  *
                    874:  * called when a new file is being edited
                    875:  */
                    876:    void
                    877: win_init(wp)
                    878:    WIN     *wp;
                    879: {
                    880:    wp->w_redr_type = NOT_VALID;
                    881:    wp->w_cursor.lnum = 1;
                    882:    wp->w_curswant = wp->w_cursor.col = 0;
                    883:    wp->w_pcmark.lnum = 1;      /* pcmark not cleared but set to line 1 */
                    884:    wp->w_pcmark.col = 0;
                    885:    wp->w_prev_pcmark.lnum = 0;
                    886:    wp->w_prev_pcmark.col = 0;
                    887:    wp->w_topline = 1;
                    888:    wp->w_botline = 2;
                    889: }
                    890:
                    891: /*
                    892:  * make window wp the current window
                    893:  */
                    894:    void
                    895: win_enter(wp, undo_sync)
                    896:    WIN     *wp;
                    897:    int     undo_sync;
                    898: {
                    899: #ifdef AUTOCMD
                    900:    int         other_buffer = FALSE;
                    901: #endif
                    902:
                    903:    if (wp == curwin)           /* nothing to do */
                    904:        return;
                    905:
                    906: #ifdef AUTOCMD
                    907:    if (curwin != NULL)
                    908:    {
                    909:        if (wp->w_buffer != curbuf)
                    910:        {
                    911:            apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
                    912:            other_buffer = TRUE;
                    913:        }
                    914:        apply_autocmds(EVENT_WINLEAVE, NULL, NULL);
                    915:    }
                    916: #endif
                    917:
                    918:        /* sync undo before leaving the current buffer */
                    919:    if (undo_sync && curbuf != wp->w_buffer)
                    920:        u_sync();
                    921:        /* may have to copy the buffer options when 'cpo' contains 'S' */
                    922:    if (wp->w_buffer != curbuf)
                    923:        buf_copy_options(curbuf, wp->w_buffer, TRUE);
                    924:    if (curwin != NULL)
                    925:        prevwin = curwin;       /* remember for CTRL-W p */
                    926:    curwin = wp;
                    927:    curbuf = wp->w_buffer;
                    928:
                    929: #ifdef AUTOCMD
                    930:    apply_autocmds(EVENT_WINENTER, NULL, NULL);
                    931:    if (other_buffer)
                    932:        apply_autocmds(EVENT_BUFENTER, NULL, NULL);
                    933: #endif
                    934:
                    935:    maketitle();
                    936:            /* set window height to desired minimal value */
                    937:    if (p_wh && curwin->w_height < p_wh)
                    938:        win_setheight((int)p_wh);
                    939: #ifdef USE_MOUSE
                    940:    setmouse();                 /* in case jumped to/from help buffer */
                    941: #endif
                    942: }
                    943:
                    944: /*
                    945:  * allocate a window structure and link it in the window list
                    946:  */
                    947:    WIN *
                    948: win_alloc(after)
                    949:    WIN     *after;
                    950: {
                    951:    WIN     *newwin;
                    952:
                    953: /*
                    954:  * allocate window structure and linesizes arrays
                    955:  */
                    956:    newwin = (WIN *)alloc((unsigned)sizeof(WIN));
                    957:    if (newwin)
                    958:    {
                    959: /*
                    960:  * most stucture members have to be zero
                    961:  */
                    962:        (void)vim_memset(newwin, 0, sizeof(WIN));
                    963: /*
                    964:  * link the window in the window list
                    965:  */
                    966:        win_append(after, newwin);
                    967:
                    968:        win_alloc_lsize(newwin);
                    969:
                    970:        /* position the display and the cursor at the top of the file. */
                    971:        newwin->w_topline = 1;
                    972:        newwin->w_botline = 2;
                    973:        newwin->w_cursor.lnum = 1;
                    974:
                    975: #ifdef USE_GUI
                    976:        /* Let the GUI know this is a new scrollbar */
                    977:        newwin->w_scrollbar.height = 0;
                    978: #endif /* USE_GUI */
                    979:    }
                    980:    return newwin;
                    981: }
                    982:
                    983: /*
                    984:  * remove window 'wp' from the window list and free the structure
                    985:  */
                    986:    void
                    987: win_free(wp)
                    988:    WIN     *wp;
                    989: {
                    990:    int     i;
                    991:
                    992:    if (prevwin == wp)
                    993:        prevwin = NULL;
                    994:    win_free_lsize(wp);
                    995:
                    996:    for (i = 0; i < wp->w_tagstacklen; ++i)
                    997:        free(wp->w_tagstack[i].tagname);
                    998:
                    999: #ifdef USE_GUI
                   1000:    if (gui.in_use)
                   1001:        gui_mch_destroy_scrollbar(wp);
                   1002: #endif /* USE_GUI */
                   1003:
                   1004:    win_remove(wp);
                   1005:    vim_free(wp);
                   1006: }
                   1007:
                   1008:    static void
                   1009: win_append(after, wp)
                   1010:    WIN     *after, *wp;
                   1011: {
                   1012:    WIN     *before;
                   1013:
                   1014:    if (after == NULL)      /* after NULL is in front of the first */
                   1015:        before = firstwin;
                   1016:    else
                   1017:        before = after->w_next;
                   1018:
                   1019:    wp->w_next = before;
                   1020:    wp->w_prev = after;
                   1021:    if (after == NULL)
                   1022:        firstwin = wp;
                   1023:    else
                   1024:        after->w_next = wp;
                   1025:    if (before == NULL)
                   1026:        lastwin = wp;
                   1027:    else
                   1028:        before->w_prev = wp;
                   1029: }
                   1030:
                   1031: /*
                   1032:  * remove window from the window list
                   1033:  */
                   1034:    static void
                   1035: win_remove(wp)
                   1036:    WIN     *wp;
                   1037: {
                   1038:    if (wp->w_prev)
                   1039:        wp->w_prev->w_next = wp->w_next;
                   1040:    else
                   1041:        firstwin = wp->w_next;
                   1042:    if (wp->w_next)
                   1043:        wp->w_next->w_prev = wp->w_prev;
                   1044:    else
                   1045:        lastwin = wp->w_prev;
                   1046: }
                   1047:
                   1048: /*
                   1049:  * allocate lsize arrays for a window
                   1050:  * return FAIL for failure, OK for success
                   1051:  */
                   1052:    int
                   1053: win_alloc_lsize(wp)
                   1054:    WIN     *wp;
                   1055: {
                   1056:    wp->w_lsize_valid = 0;
                   1057:    wp->w_lsize_lnum = (linenr_t *) malloc((size_t) (Rows * sizeof(linenr_t)));
                   1058:    wp->w_lsize = (char_u *)malloc((size_t) Rows);
                   1059:    if (wp->w_lsize_lnum == NULL || wp->w_lsize == NULL)
                   1060:    {
                   1061:        win_free_lsize(wp);     /* one of the two may have worked */
                   1062:        wp->w_lsize_lnum = NULL;
                   1063:        wp->w_lsize = NULL;
                   1064:        return FAIL;
                   1065:    }
                   1066:    return OK;
                   1067: }
                   1068:
                   1069: /*
                   1070:  * free lsize arrays for a window
                   1071:  */
                   1072:    void
                   1073: win_free_lsize(wp)
                   1074:    WIN     *wp;
                   1075: {
                   1076:    vim_free(wp->w_lsize_lnum);
                   1077:    vim_free(wp->w_lsize);
                   1078: }
                   1079:
                   1080: /*
                   1081:  * call this fuction whenever Rows changes value
                   1082:  */
                   1083:    void
                   1084: screen_new_rows()
                   1085: {
                   1086:    WIN     *wp;
                   1087:    int     extra_lines;
                   1088:
                   1089:    if (firstwin == NULL)       /* not initialized yet */
                   1090:        return;
                   1091: /*
                   1092:  * the number of extra lines is the difference between the position where
                   1093:  * the command line should be and where it is now
                   1094:  */
                   1095:    compute_cmdrow();
                   1096:    extra_lines = Rows - p_ch - cmdline_row;
                   1097:    if (extra_lines < 0)                        /* reduce windows height */
                   1098:    {
                   1099:        for (wp = lastwin; wp; wp = wp->w_prev)
                   1100:        {
                   1101:            if (wp->w_height - MIN_ROWS < -extra_lines)
                   1102:            {
                   1103:                extra_lines += wp->w_height - MIN_ROWS;
                   1104:                win_new_height(wp, MIN_ROWS);
                   1105:            }
                   1106:            else
                   1107:            {
                   1108:                win_new_height(wp, wp->w_height + extra_lines);
                   1109:                break;
                   1110:            }
                   1111:        }
                   1112:        (void)win_comp_pos();               /* compute w_winpos */
                   1113:    }
                   1114:    else if (extra_lines > 0)               /* increase height of last window */
                   1115:        win_new_height(lastwin, lastwin->w_height + extra_lines);
                   1116:
                   1117:    compute_cmdrow();
                   1118:
                   1119:    if (p_ea)
                   1120:        win_equal(curwin, FALSE);
                   1121: }
                   1122:
                   1123: /*
                   1124:  * update the w_winpos field for all windows
                   1125:  * returns the row just after the last window
                   1126:  */
                   1127:    static int
                   1128: win_comp_pos()
                   1129: {
                   1130:    WIN     *wp;
                   1131:    int     row;
                   1132:
                   1133:    row = 0;
                   1134:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                   1135:    {
                   1136:        if (wp->w_winpos != row)        /* if position changes, redraw */
                   1137:        {
                   1138:            wp->w_winpos = row;
                   1139:            wp->w_redr_type = NOT_VALID;
                   1140:            wp->w_redr_status = TRUE;
                   1141:        }
                   1142:        row += wp->w_height + wp->w_status_height;
                   1143:    }
                   1144:    return row;
                   1145: }
                   1146:
                   1147: /*
                   1148:  * set current window height
                   1149:  */
                   1150:    void
                   1151: win_setheight(height)
                   1152:    int     height;
                   1153: {
                   1154:    WIN     *wp;
                   1155:    int     room;               /* total number of lines available */
                   1156:    int     take;               /* number of lines taken from other windows */
                   1157:    int     room_cmdline;       /* lines available from cmdline */
                   1158:    int     row;
                   1159:    int     run;
                   1160:
                   1161:    if (height < MIN_ROWS)      /* need at least some lines */
                   1162:        height = MIN_ROWS;
                   1163: /*
                   1164:  * compute the room we have from all the windows
                   1165:  */
                   1166:    room = MIN_ROWS;            /* count the MIN_ROWS for the current window */
                   1167:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                   1168:        room += wp->w_height - MIN_ROWS;
                   1169: /*
                   1170:  * compute the room available from the command line
                   1171:  */
                   1172:    room_cmdline = Rows - p_ch - cmdline_row;
                   1173: /*
                   1174:  * limit new height to the room available
                   1175:  */
                   1176:    if (height > room + room_cmdline)       /* can't make it that large */
                   1177:        height = room + room_cmdline;       /* use all available room */
                   1178: /*
                   1179:  * compute the number of lines we will take from the windows (can be negative)
                   1180:  */
                   1181:    take = height - curwin->w_height;
                   1182:    if (take == 0)                          /* no change, nothing to do */
                   1183:        return;
                   1184:
                   1185:    if (take > 0)
                   1186:    {
                   1187:        take -= room_cmdline;               /* use lines from cmdline first */
                   1188:        if (take < 0)
                   1189:            take = 0;
                   1190:    }
                   1191: /*
                   1192:  * set the current window to the new height
                   1193:  */
                   1194:    win_new_height(curwin, height);
                   1195:
                   1196: /*
                   1197:  * First take lines from the windows below the current window.
                   1198:  * If that is not enough, takes lines from windows above the current window.
                   1199:  */
                   1200:    for (run = 0; run < 2; ++run)
                   1201:    {
                   1202:        if (run == 0)
                   1203:            wp = curwin->w_next;        /* 1st run: start with next window */
                   1204:        else
                   1205:            wp = curwin->w_prev;        /* 2nd run: start with prev window */
                   1206:        while (wp != NULL && take != 0)
                   1207:        {
                   1208:            if (wp->w_height - take < MIN_ROWS)
                   1209:            {
                   1210:                take -= wp->w_height - MIN_ROWS;
                   1211:                win_new_height(wp, MIN_ROWS);
                   1212:            }
                   1213:            else
                   1214:            {
                   1215:                win_new_height(wp, wp->w_height - take);
                   1216:                take = 0;
                   1217:            }
                   1218:            if (run == 0)
                   1219:                wp = wp->w_next;
                   1220:            else
                   1221:                wp = wp->w_prev;
                   1222:        }
                   1223:    }
                   1224:
                   1225: /* recompute the window positions */
                   1226:    row = win_comp_pos();
                   1227:
                   1228: /*
                   1229:  * If there is extra space created between the last window and the command line,
                   1230:  * clear it.
                   1231:  */
                   1232:    screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ');
                   1233:    cmdline_row = row;
                   1234:
                   1235:    updateScreen(NOT_VALID);
                   1236: }
                   1237:
                   1238: #ifdef USE_MOUSE
                   1239:    void
                   1240: win_drag_status_line(offset)
                   1241:    int     offset;
                   1242: {
                   1243:    WIN     *wp;
                   1244:    int     room;
                   1245:    int     row;
                   1246:    int     up;             /* if TRUE, drag status line up, otherwise down */
                   1247:
                   1248:    if (offset < 0)
                   1249:    {
                   1250:        up = TRUE;
                   1251:        offset = -offset;
                   1252:    }
                   1253:    else
                   1254:        up = FALSE;
                   1255:
                   1256:    if (up) /* drag up */
                   1257:    {
                   1258:        room = 0;
                   1259:        for (wp = curwin; wp != NULL && room < offset; wp = wp->w_prev)
                   1260:            room += wp->w_height - MIN_ROWS;
                   1261:        wp = curwin->w_next;                /* put wp at window that grows */
                   1262:    }
                   1263:    else    /* drag down */
                   1264:    {
                   1265:        /*
                   1266:         * Only dragging the last status line can reduce p_ch.
                   1267:         */
                   1268:        room = Rows - cmdline_row;
                   1269:        if (curwin->w_next == NULL)
                   1270:            room -= 1;
                   1271:        else
                   1272:            room -= p_ch;
                   1273:        for (wp = curwin->w_next; wp != NULL && room < offset; wp = wp->w_next)
                   1274:            room += wp->w_height - MIN_ROWS;
                   1275:        wp = curwin;                        /* put wp at window that grows */
                   1276:    }
                   1277:
                   1278:    if (room < offset)      /* Not enough room */
                   1279:        offset = room;      /* Move as far as we can */
                   1280:    if (offset <= 0)
                   1281:        return;
                   1282:
                   1283:    if (wp != NULL)         /* grow window wp by offset lines */
                   1284:        win_new_height(wp, wp->w_height + offset);
                   1285:
                   1286:    if (up)
                   1287:        wp = curwin;                /* current window gets smaller */
                   1288:    else
                   1289:        wp = curwin->w_next;        /* next window gets smaller */
                   1290:
                   1291:    while (wp != NULL && offset > 0)
                   1292:    {
                   1293:        if (wp->w_height - offset < MIN_ROWS)
                   1294:        {
                   1295:            offset -= wp->w_height - MIN_ROWS;
                   1296:            win_new_height(wp, MIN_ROWS);
                   1297:        }
                   1298:        else
                   1299:        {
                   1300:            win_new_height(wp, wp->w_height - offset);
                   1301:            offset = 0;
                   1302:        }
                   1303:        if (up)
                   1304:            wp = wp->w_prev;
                   1305:        else
                   1306:            wp = wp->w_next;
                   1307:    }
                   1308:    row = win_comp_pos();
                   1309:    screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ');
                   1310:    cmdline_row = row;
                   1311:    p_ch = Rows - cmdline_row;
                   1312:    updateScreen(NOT_VALID);
                   1313:    showmode();
                   1314: }
                   1315: #endif /* USE_MOUSE */
                   1316:
                   1317: /*
                   1318:  * Set new window height.
                   1319:  */
                   1320:    static void
                   1321: win_new_height(wp, height)
                   1322:    WIN     *wp;
                   1323:    int     height;
                   1324: {
                   1325:    /* should adjust topline to keep cursor at same relative postition */
                   1326:
                   1327:    wp->w_height = height;
                   1328:    win_comp_scroll(wp);
                   1329:    wp->w_redr_type = NOT_VALID;
                   1330:    wp->w_redr_status = TRUE;
                   1331: }
                   1332:
                   1333:    void
                   1334: win_comp_scroll(wp)
                   1335:    WIN     *wp;
                   1336: {
                   1337:    wp->w_p_scroll = (wp->w_height >> 1);
                   1338:    if (wp->w_p_scroll == 0)
                   1339:        wp->w_p_scroll = 1;
                   1340: }
                   1341:
                   1342: /*
                   1343:  * command_height: called whenever p_ch has been changed
                   1344:  */
                   1345:    void
                   1346: command_height()
                   1347: {
                   1348:    int     current;
                   1349:
                   1350:    current = Rows - cmdline_row;
                   1351:    if (p_ch > current)             /* p_ch got bigger */
                   1352:    {
                   1353:        if (lastwin->w_height - (p_ch - current) < MIN_ROWS)
                   1354:        {
                   1355:            emsg(e_noroom);
                   1356:            p_ch = lastwin->w_height - MIN_ROWS + current;
                   1357:        }
                   1358:        /* clear the lines added to cmdline */
                   1359:        screen_fill((int)(Rows - p_ch), (int)Rows, 0, (int)Columns, ' ', ' ');
                   1360:    }
                   1361:    win_new_height(lastwin, lastwin->w_height + current - (int)p_ch);
                   1362:    cmdline_row = Rows - p_ch;
                   1363:    redraw_cmdline = TRUE;
                   1364: }
                   1365:
                   1366:    void
                   1367: last_status()
                   1368: {
                   1369:    if (lastwin->w_status_height)
                   1370:    {
                   1371:                    /* remove status line */
                   1372:        if (p_ls == 0 || (p_ls == 1 && firstwin == lastwin))
                   1373:        {
                   1374:            win_new_height(lastwin, lastwin->w_height + 1);
                   1375:            lastwin->w_status_height = 0;
                   1376:        }
                   1377:    }
                   1378:    else
                   1379:    {
                   1380:                    /* add status line */
                   1381:        if (p_ls == 2 || (p_ls == 1 && firstwin != lastwin))
                   1382:        {
                   1383:            if (lastwin->w_height <= MIN_ROWS)      /* can't do it */
                   1384:                emsg(e_noroom);
                   1385:            else
                   1386:            {
                   1387:                win_new_height(lastwin, lastwin->w_height - 1);
                   1388:                lastwin->w_status_height = 1;
                   1389:            }
                   1390:        }
                   1391:    }
                   1392: }
                   1393:
                   1394: /*
                   1395:  * file_name_at_cursor()
                   1396:  *
                   1397:  * Return the name of the file under (or to the right of) the cursor.  The
                   1398:  * p_path variable is searched if the file name does not start with '/'.
                   1399:  * The string returned has been alloc'ed and should be freed by the caller.
                   1400:  * NULL is returned if the file name or file is not found.
                   1401:  */
                   1402:    char_u *
                   1403: file_name_at_cursor(options)
                   1404:    int     options;
                   1405: {
                   1406:    return get_file_name_in_path(ml_get_curline(),
                   1407:                                               curwin->w_cursor.col, options);
                   1408: }
                   1409: /* options:
                   1410:  * FNAME_MESS      give error messages
                   1411:  * FNAME_EXP       expand to path
                   1412:  * FNAME_HYP       check for hypertext link
                   1413:  */
                   1414:    char_u *
                   1415: get_file_name_in_path(ptr, col, options)
                   1416:    char_u  *ptr;
                   1417:    int     col;
                   1418:    int     options;
                   1419: {
                   1420:    char_u  *dir;
                   1421:    char_u  *file_name;
                   1422:    char_u  save_char;
                   1423:    char_u  *curr_path = NULL;
                   1424:    int     curr_path_len;
                   1425:    int     len;
                   1426:
                   1427:        /* search forward for what could be the start of a file name */
                   1428:    while (ptr[col] != NUL && !isfilechar(ptr[col]))
                   1429:        ++col;
                   1430:    if (ptr[col] == NUL)            /* nothing found */
                   1431:    {
                   1432:        if (options & FNAME_MESS)
                   1433:            EMSG("No file name under cursor");
                   1434:        return NULL;
                   1435:    }
                   1436:
                   1437:        /* search backward for char that cannot be in a file name */
                   1438:    while (col >= 0 && isfilechar(ptr[col]))
                   1439:        --col;
                   1440:    ptr += col + 1;
                   1441:    col = 0;
                   1442:
                   1443:        /* search forward for a char that cannot be in a file name */
                   1444:    while (isfilechar(ptr[col]))
                   1445:        ++col;
                   1446:
                   1447:    if (options & FNAME_HYP)
                   1448:    {
                   1449:        /* For hypertext links, ignore the name of the machine.
                   1450:         * Such a link looks like "type://machine/path". Only "/path" is used.
                   1451:         * First search for the string "://", then for the extra '/'
                   1452:         */
                   1453:        if ((file_name = vim_strchr(ptr, ':')) != NULL &&
                   1454:                STRNCMP(file_name, "://", (size_t)3) == 0 &&
                   1455:                (file_name = vim_strchr(file_name + 3, '/')) != NULL &&
                   1456:                file_name < ptr + col)
                   1457:        {
                   1458:            col -= file_name - ptr;
                   1459:            ptr = file_name;
                   1460:            if (ptr[1] == '~')      /* skip '/' for /~user/path */
                   1461:            {
                   1462:                ++ptr;
                   1463:                --col;
                   1464:            }
                   1465:        }
                   1466:    }
                   1467:
                   1468:    if (!(options & FNAME_EXP))
                   1469:        return strnsave(ptr, col);
                   1470:
                   1471:        /* copy file name into NameBuff, expanding environment variables */
                   1472:    save_char = ptr[col];
                   1473:    ptr[col] = NUL;
                   1474:    expand_env(ptr, NameBuff, MAXPATHL);
                   1475:    ptr[col] = save_char;
                   1476:
                   1477:    if (isFullName(NameBuff))           /* absolute path */
                   1478:    {
                   1479:        if ((file_name = strsave(NameBuff)) == NULL)
                   1480:            return NULL;
                   1481:        if (getperm(file_name) >= 0)
                   1482:            return file_name;
                   1483:        if (options & FNAME_MESS)
                   1484:        {
                   1485:            sprintf((char *)IObuff, "Can't find file `%s'", NameBuff);
                   1486:            emsg(IObuff);
                   1487:        }
                   1488:    }
                   1489:    else                            /* relative path, use 'path' option */
                   1490:    {
                   1491:        if (curbuf->b_xfilename != NULL)
                   1492:        {
                   1493:            curr_path = curbuf->b_xfilename;
                   1494:            ptr = gettail(curr_path);
                   1495:            curr_path_len = ptr - curr_path;
                   1496:        }
                   1497:        else
                   1498:            curr_path_len = 0;
                   1499:        if ((file_name = alloc((int)(curr_path_len + STRLEN(p_path) +
                   1500:                                            STRLEN(NameBuff) + 3))) == NULL)
                   1501:            return NULL;
                   1502:
                   1503:        for (dir = p_path; *dir;)
                   1504:        {
                   1505:            len = copy_option_part(&dir, file_name, 31000, " ,");
                   1506:            /* len == 0 means: use current directory */
                   1507:            if (len != 0)
                   1508:            {
                   1509:                                /* Look for file relative to current file */
                   1510:                if (file_name[0] == '.' && curr_path_len > 0)
                   1511:                {
                   1512:                    if (len == 1)       /* just a "." */
                   1513:                        len = 0;
                   1514:                    else                /* "./path": move "path" */
                   1515:                    {
                   1516:                        len -= 2;
                   1517:                        vim_memmove(file_name + curr_path_len, file_name + 2,
                   1518:                                                                 (size_t)len);
                   1519:                    }
                   1520:                    STRNCPY(file_name, curr_path, curr_path_len);
                   1521:                    len += curr_path_len;
                   1522:                }
                   1523:                if (!ispathsep(file_name[len - 1]))
                   1524:                    file_name[len++] = PATHSEP;
                   1525:            }
                   1526:            STRCPY(file_name + len, NameBuff);
                   1527:            if (getperm(file_name) >= 0)
                   1528:                return file_name;
                   1529:        }
                   1530:        if (options & FNAME_MESS)
                   1531:            EMSG2("Can't find file \"%s\" in path", NameBuff);
                   1532:    }
                   1533:    vim_free(file_name);            /* file doesn't exist */
                   1534:    return NULL;
                   1535: }
                   1536:
                   1537: /*
                   1538:  * Return the minimal number of rows that is needed on the screen to display
                   1539:  * the current number of windows.
                   1540:  */
                   1541:    int
                   1542: min_rows()
                   1543: {
                   1544:    WIN     *wp;
                   1545:    int     total;
                   1546:
                   1547:    if (firstwin == NULL)       /* not initialized yet */
                   1548:        return MIN_ROWS + 1;    /* one window plus command line */
                   1549:
                   1550:    total = p_ch;       /* count the room for the status line */
                   1551:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                   1552:        total += MIN_ROWS + wp->w_status_height;
                   1553:    return total;
                   1554: }
                   1555:
                   1556: /*
                   1557:  * Return TRUE if there is only one window, not counting a help window, unless
                   1558:  * it is the current window.
                   1559:  */
                   1560:    int
                   1561: only_one_window()
                   1562: {
                   1563:    int     count = 0;
                   1564:    WIN     *wp;
                   1565:
                   1566:    for (wp = firstwin; wp != NULL; wp = wp->w_next)
                   1567:        if (!wp->w_buffer->b_help || wp == curwin)
                   1568:            ++count;
                   1569:    return (count <= 1);
                   1570: }