home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / amiga / vim46src.lha / vim-4.6 / src / window.c < prev   
Encoding:
C/C++ Source or Header  |  1997-02-11  |  34.9 KB  |  1,647 lines

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