[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     ! 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: }