home *** CD-ROM | disk | FTP | other *** search
- /* vi:ts=4:sw=4
- *
- * VIM - Vi IMproved by Bram Moolenaar
- *
- * Read the file "credits.txt" for a list of people who contributed.
- * Read the file "uganda.txt" for copying and usage conditions.
- */
-
- #include "vim.h"
- #include "globals.h"
- #include "proto.h"
- #include "param.h"
-
- static int win_comp_pos __ARGS((void));
- static void win_exchange __ARGS((long));
- static void win_rotate __ARGS((int, int));
- static void win_append __ARGS((WIN *, WIN *));
- static void win_remove __ARGS((WIN *));
-
- static WIN *prevwin = NULL; /* previous window */
-
- /*
- * all CTRL-W window commands are handled here, called from normal().
- */
- void
- do_window(nchar, Prenum)
- int nchar;
- long Prenum;
- {
- long Prenum1;
- WIN *wp;
- char_u *ptr;
-
- if (Prenum == 0)
- Prenum1 = 1;
- else
- Prenum1 = Prenum;
-
- switch (nchar)
- {
- /* split current window in two parts */
- case 'S':
- case Ctrl('S'):
- case 's': VIsual.lnum = 0; /* stop Visual mode */
- win_split(Prenum, TRUE);
- break;
-
- /* open new window */
- case Ctrl('N'):
- case 'n': VIsual.lnum = 0; /* stop Visual mode */
- stuffcharReadbuff(':');
- if (Prenum)
- stuffnumReadbuff(Prenum); /* window height */
- stuffReadbuff((char_u *)"new\n"); /* it is cmdline.c */
- break;
-
- /* quit current window */
- case Ctrl('Q'):
- case 'q': VIsual.lnum = 0; /* stop Visual mode */
- stuffReadbuff((char_u *)":quit\n"); /* it is cmdline.c */
- break;
-
- /* close current window */
- case Ctrl('C'):
- case 'c': VIsual.lnum = 0; /* stop Visual mode */
- stuffReadbuff((char_u *)":close\n"); /* it is cmdline.c */
- break;
-
- /* close all but current window */
- case Ctrl('O'):
- case 'o': VIsual.lnum = 0; /* stop Visual mode */
- stuffReadbuff((char_u *)":only\n"); /* it is cmdline.c */
- break;
-
- /* cursor to next window */
- case 'j':
- case K_DARROW:
- case Ctrl('J'):
- VIsual.lnum = 0; /* stop Visual mode */
- for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
- wp = wp->w_next)
- ;
- win_enter(wp, TRUE);
- cursupdate();
- break;
-
- /* cursor to next window with wrap around */
- case Ctrl('W'):
- case 'w':
- VIsual.lnum = 0; /* stop Visual mode */
- if (lastwin == firstwin) /* just one window */
- beep();
- else
- {
- if (Prenum) /* go to specified window */
- {
- for (wp = firstwin; --Prenum > 0; )
- {
- if (wp->w_next == NULL)
- break;
- else
- wp = wp->w_next;
- }
- }
- else /* go to next window */
- {
- wp = curwin->w_next;
- if (wp == NULL)
- wp = firstwin; /* wrap around */
- }
- win_enter(wp, TRUE);
- cursupdate();
- }
- break;
-
- /* cursor to window above */
- case 'k':
- case K_UARROW:
- case Ctrl('K'):
- VIsual.lnum = 0; /* stop Visual mode */
- for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
- wp = wp->w_prev)
- ;
- win_enter(wp, TRUE);
- cursupdate();
- break;
-
- /* cursor to last accessed (previous) window */
- case 'p':
- case Ctrl('P'):
- VIsual.lnum = 0; /* stop Visual mode */
- if (prevwin == NULL)
- beep();
- else
- {
- win_enter(prevwin, TRUE);
- cursupdate();
- }
- break;
-
- /* exchange current and next window */
- case 'x':
- case Ctrl('X'):
- win_exchange(Prenum);
- break;
-
- /* rotate windows downwards */
- case Ctrl('R'):
- case 'r': VIsual.lnum = 0; /* stop Visual mode */
- win_rotate(FALSE, (int)Prenum1); /* downwards */
- break;
-
- /* rotate windows upwards */
- case 'R': VIsual.lnum = 0; /* stop Visual mode */
- win_rotate(TRUE, (int)Prenum1); /* upwards */
- break;
-
- /* make all windows the same height */
- case '=': win_equal(NULL, TRUE);
- break;
-
- /* increase current window height */
- case '+': win_setheight(curwin->w_height + (int)Prenum1);
- break;
-
- /* decrease current window height */
- case '-': win_setheight(curwin->w_height - (int)Prenum1);
- break;
-
- /* set current window height */
- case Ctrl('_'):
- case '_': win_setheight(Prenum ? (int)Prenum : 9999);
- break;
-
- /* jump to tag and split window if tag exists */
- case ']':
- case Ctrl(']'):
- VIsual.lnum = 0; /* stop Visual mode */
- postponed_split = TRUE;
- stuffcharReadbuff(Ctrl(']'));
- break;
-
- /* edit file name under cursor in a new window */
- case 'f':
- case Ctrl('F'):
- VIsual.lnum = 0; /* stop Visual mode */
- ptr = file_name_at_cursor();
- if (ptr == NULL)
- beep();
- else
- {
- stuffReadbuff((char_u *) ":split ");
- stuffReadbuff(ptr);
- stuffReadbuff((char_u *) "\n");
- free(ptr);
- }
- break;
-
- default: beep();
- break;
- }
- }
-
- /*
- * split the current window, implements CTRL-W s and :split
- *
- * new_height is the height for the new window, 0 to make half of current height
- * redraw is TRUE when redraw now
- *
- * return FAIL for failure, OK otherwise
- */
- int
- win_split(new_height, redraw)
- long new_height;
- int redraw;
- {
- WIN *wp;
- linenr_t lnum;
- int h;
- int i;
- int need_status;
- int do_equal = (p_ea && new_height == 0);
- int needed;
- int available;
-
- /* add a status line when p_ls == 1 and splitting the first window */
- if (lastwin == firstwin && p_ls == 1 && curwin->w_status_height == 0)
- need_status = STATUS_HEIGHT;
- else
- need_status = 0;
-
- /*
- * check if we are able to split the current window and compute its height
- */
- available = curwin->w_height;
- needed = 2 * MIN_ROWS + STATUS_HEIGHT + need_status;
- if (p_ea)
- {
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp != curwin)
- {
- available += wp->w_height;
- needed += MIN_ROWS;
- }
- }
- if (available < needed)
- {
- EMSG(e_noroom);
- return FAIL;
- }
- if (need_status)
- {
- curwin->w_status_height = STATUS_HEIGHT;
- curwin->w_height -= STATUS_HEIGHT;
- }
- if (new_height == 0)
- new_height = curwin->w_height / 2;
-
- if (new_height > curwin->w_height - MIN_ROWS - STATUS_HEIGHT)
- new_height = curwin->w_height - MIN_ROWS - STATUS_HEIGHT;
-
- if (new_height < MIN_ROWS)
- new_height = MIN_ROWS;
-
- /* if it doesn't fit in the current window, need win_equal() */
- if (curwin->w_height - new_height - STATUS_HEIGHT < MIN_ROWS)
- do_equal = TRUE;
- /*
- * allocate new window structure and link it in the window list
- */
- if (p_sb) /* new window below current one */
- wp = win_alloc(curwin);
- else
- wp = win_alloc(curwin->w_prev);
- if (wp == NULL)
- return FAIL;
- /*
- * compute the new screen positions
- */
- wp->w_height = new_height;
- win_comp_scroll(wp);
- curwin->w_height -= new_height + STATUS_HEIGHT;
- win_comp_scroll(curwin);
- if (p_sb) /* new window below current one */
- {
- wp->w_winpos = curwin->w_winpos + curwin->w_height + STATUS_HEIGHT;
- wp->w_status_height = curwin->w_status_height;
- curwin->w_status_height = STATUS_HEIGHT;
- }
- else /* new window above current one */
- {
- wp->w_winpos = curwin->w_winpos;
- wp->w_status_height = STATUS_HEIGHT;
- curwin->w_winpos = wp->w_winpos + wp->w_height + STATUS_HEIGHT;
- }
- /*
- * make the contents of the new window the same as the current one
- */
- wp->w_buffer = curbuf;
- curbuf->b_nwindows++;
- wp->w_cursor = curwin->w_cursor;
- wp->w_row = curwin->w_row;
- wp->w_col = curwin->w_col;
- wp->w_virtcol = curwin->w_virtcol;
- wp->w_curswant = curwin->w_curswant;
- wp->w_set_curswant = curwin->w_set_curswant;
- wp->w_empty_rows = curwin->w_empty_rows;
- wp->w_leftcol = curwin->w_leftcol;
- wp->w_pcmark = curwin->w_pcmark;
- wp->w_prev_pcmark = curwin->w_prev_pcmark;
-
- wp->w_arg_idx = curwin->w_arg_idx;
- /*
- * copy tagstack and options from existing window
- */
- for (i = 0; i < curwin->w_tagstacklen; i++)
- {
- wp->w_tagstack[i].fmark = curwin->w_tagstack[i].fmark;
- wp->w_tagstack[i].tagname = strsave(curwin->w_tagstack[i].tagname);
- }
- wp->w_tagstackidx = curwin->w_tagstackidx;
- wp->w_tagstacklen = curwin->w_tagstacklen;
- win_copy_options(curwin, wp);
- /*
- * Both windows need redrawing
- */
- wp->w_redr_type = NOT_VALID;
- wp->w_redr_status = TRUE;
- curwin->w_redr_type = NOT_VALID;
- curwin->w_redr_status = TRUE;
- /*
- * Cursor is put in middle of window in both windows
- */
- if (wp->w_height < curwin->w_height) /* use smallest of two heights */
- h = wp->w_height;
- else
- h = curwin->w_height;
- h >>= 1;
- for (lnum = wp->w_cursor.lnum; lnum > 1; --lnum)
- {
- h -= plines(lnum);
- if (h <= 0)
- break;
- }
- wp->w_topline = lnum;
- curwin->w_topline = lnum;
- /*
- * make the new window the current window and redraw
- */
- if (do_equal)
- win_equal(wp, FALSE);
- win_enter(wp, FALSE);
- if (redraw)
- updateScreen(NOT_VALID);
- return OK;
- }
-
- /*
- * make 'count' windows on the screen
- * return actual number of windows on the screen
- * called when there is just one window, filling the whole screen.
- */
- int
- make_windows(count)
- int count;
- {
- int maxcount;
- int todo;
- int p_sb_save;
-
- /*
- * each window needs at least MIN_ROWS lines and a status line
- */
- maxcount = (curwin->w_height + curwin->w_status_height) /
- (MIN_ROWS + STATUS_HEIGHT);
- if (count > maxcount)
- count = maxcount;
-
- /*
- * add status line now, otherwise first window will be too big
- */
- if ((p_ls == 2 || (count > 1 && p_ls == 1)) && curwin->w_status_height == 0)
- {
- curwin->w_status_height = STATUS_HEIGHT;
- curwin->w_height -= STATUS_HEIGHT;
- }
-
- /*
- * set 'splitbelow' off for a moment, don't what that now
- */
- p_sb_save = p_sb;
- p_sb = FALSE;
- /* todo is number of windows left to create */
- for (todo = count - 1; todo > 0; --todo)
- if (win_split((long)(curwin->w_height - (curwin->w_height - todo
- * STATUS_HEIGHT) / (todo + 1) - STATUS_HEIGHT), FALSE) == FAIL)
- break;
- p_sb = p_sb_save;
-
- /* return actual number of windows */
- return (count - todo);
- }
-
- /*
- * Exchange current and next window
- */
- static void
- win_exchange(Prenum)
- long Prenum;
- {
- WIN *wp;
- WIN *wp2;
- int temp;
-
- if (lastwin == firstwin) /* just one window */
- {
- beep();
- return;
- }
-
- /*
- * find window to exchange with
- */
- if (Prenum)
- {
- wp = firstwin;
- while (wp != NULL && --Prenum > 0)
- wp = wp->w_next;
- }
- else if (curwin->w_next != NULL) /* Swap with next */
- wp = curwin->w_next;
- else /* Swap last window with previous */
- wp = curwin->w_prev;
-
- if (wp == curwin || wp == NULL)
- return;
-
- /*
- * 1. remove curwin from the list. Remember after which window it was in wp2
- * 2. insert curwin before wp in the list
- * if wp != wp2
- * 3. remove wp from the list
- * 4. insert wp after wp2
- * 5. exchange the status line height
- */
- wp2 = curwin->w_prev;
- win_remove(curwin);
- win_append(wp->w_prev, curwin);
- if (wp != wp2)
- {
- win_remove(wp);
- win_append(wp2, wp);
- }
- temp = curwin->w_status_height;
- curwin->w_status_height = wp->w_status_height;
- wp->w_status_height = temp;
-
- win_comp_pos(); /* recompute window positions */
-
- win_enter(wp, TRUE);
- cursupdate();
- updateScreen(CLEAR);
- }
-
- /*
- * rotate windows: if upwards TRUE the second window becomes the first one
- * if upwards FALSE the first window becomes the second one
- */
- static void
- win_rotate(upwards, count)
- int upwards;
- int count;
- {
- WIN *wp;
- int height;
-
- if (firstwin == lastwin) /* nothing to do */
- {
- beep();
- return;
- }
- while (count--)
- {
- if (upwards) /* first window becomes last window */
- {
- wp = firstwin;
- win_remove(wp);
- win_append(lastwin, wp);
- wp = lastwin->w_prev; /* previously last window */
- }
- else /* last window becomes first window */
- {
- wp = lastwin;
- win_remove(lastwin);
- win_append(NULL, wp);
- wp = firstwin; /* previously last window */
- }
- /* exchange status height of old and new last window */
- height = lastwin->w_status_height;
- lastwin->w_status_height = wp->w_status_height;
- wp->w_status_height = height;
-
- /* recompute w_winpos for all windows */
- (void) win_comp_pos();
- }
-
- cursupdate();
- updateScreen(CLEAR);
- }
-
- /*
- * make all windows the same height
- */
- void
- win_equal(next_curwin, redraw)
- WIN *next_curwin; /* pointer to current window to be */
- int redraw;
- {
- int total;
- int less;
- int wincount;
- int winpos;
- int temp;
- WIN *wp;
- int new_height;
-
- /*
- * count the number of lines available
- */
- total = 0;
- wincount = 0;
- for (wp = firstwin; wp; wp = wp->w_next)
- {
- total += wp->w_height - MIN_ROWS;
- wincount++;
- }
-
- /*
- * if next_curwin given and 'winheight' set, make next_curwin p_wh lines
- */
- if (next_curwin != NULL && p_wh)
- {
- if (p_wh - MIN_ROWS > total) /* all lines go to current window */
- less = total;
- else
- {
- less = p_wh - MIN_ROWS - total / wincount;
- if (less < 0)
- less = 0;
- }
- }
- else
- less = 0;
-
-
- /*
- * spread the available lines over the windows
- */
- winpos = 0;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- {
- if (wp == next_curwin && less)
- {
- less = 0;
- temp = p_wh - MIN_ROWS;
- if (temp > total)
- temp = total;
- }
- else
- temp = (total - less + (wincount >> 1)) / wincount;
- new_height = MIN_ROWS + temp;
- if (wp->w_winpos != winpos || wp->w_height != new_height)
- {
- wp->w_redr_type = NOT_VALID;
- wp->w_redr_status = TRUE;
- }
- wp->w_winpos = winpos;
- wp->w_height = new_height;
- win_comp_scroll(wp);
- total -= temp;
- --wincount;
- winpos += wp->w_height + wp->w_status_height;
- }
- if (redraw)
- {
- cursupdate();
- updateScreen(CLEAR);
- }
- }
-
- /*
- * close current window
- * If "free_buf" is TRUE related buffer may be freed.
- *
- * called by :quit, :close, :xit, :wq and findtag()
- */
- void
- close_window(free_buf)
- int free_buf;
- {
- WIN *wp;
-
- if (lastwin == firstwin)
- {
- EMSG("Cannot close last window");
- return;
- }
-
- /*
- * Close the link to the buffer.
- */
- close_buffer(curbuf, free_buf, FALSE);
-
- /*
- * Remove the window.
- */
- if (curwin->w_prev == NULL) /* freed space goes to next window */
- {
- wp = curwin->w_next;
- wp->w_winpos = curwin->w_winpos;
- }
- else /* freed space goes to previous window */
- wp = curwin->w_prev;
- wp->w_height += curwin->w_height + curwin->w_status_height;
-
- win_free(curwin);
- curwin = NULL;
- if (p_ea)
- win_equal(wp, FALSE);
- win_enter(wp, FALSE);
- /*
- * if last window has status line now and we don't want one,
- * remove the status line
- */
- if (lastwin->w_status_height &&
- (p_ls == 0 || (p_ls == 1 && firstwin == lastwin)))
- {
- lastwin->w_height += lastwin->w_status_height;
- lastwin->w_status_height = 0;
- win_comp_scroll(lastwin);
- }
- win_comp_scroll(curwin);
- updateScreen(NOT_VALID);
- }
-
- /*
- * close all windows except current one
- * buffers in the windows become hidden
- *
- * called by :only and do_arg_all();
- */
- void
- close_others(message)
- int message;
- {
- WIN *wp;
- WIN *nextwp;
-
- if (lastwin == firstwin)
- {
- if (message)
- EMSG("Already only one window");
- return;
- }
-
- for (wp = firstwin; wp != NULL; wp = nextwp)
- {
- nextwp = wp->w_next;
- if (wp == curwin) /* don't close current window */
- continue;
- /*
- * Close the link to the buffer.
- */
- close_buffer(wp->w_buffer, FALSE, FALSE);
-
- /*
- * Remove the window. All lines go to current window.
- */
- curwin->w_height += wp->w_height + wp->w_status_height;
-
- win_free(wp);
- }
- /*
- * if current window has status line and we don't want one,
- * remove the status line
- */
- if (curwin->w_status_height && p_ls != 2)
- {
- curwin->w_height += curwin->w_status_height;
- curwin->w_status_height = 0;
- }
- curwin->w_winpos = 0; /* put current window at top of the screen */
- win_comp_scroll(curwin);
- if (message)
- updateScreen(NOT_VALID);
- }
-
- /*
- * init the cursor in the window
- *
- * called when a new file is being edited
- */
- void
- win_init(wp)
- WIN *wp;
- {
- wp->w_redr_type = NOT_VALID;
- wp->w_cursor.lnum = 1;
- wp->w_curswant = wp->w_cursor.col = 0;
- wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
- wp->w_pcmark.col = 0;
- wp->w_prev_pcmark.lnum = 0;
- wp->w_prev_pcmark.col = 0;
- wp->w_topline = 1;
- wp->w_botline = 2;
- }
-
- /*
- * make window wp the current window
- */
- void
- win_enter(wp, undo_sync)
- WIN *wp;
- int undo_sync;
- {
- if (wp == curwin) /* nothing to do */
- return;
-
- /* sync undo before leaving the current buffer */
- if (undo_sync && curbuf != wp->w_buffer)
- u_sync();
- if (curwin != NULL)
- prevwin = curwin; /* remember for CTRL-W p */
- curwin = wp;
- curbuf = wp->w_buffer;
- maketitle();
- /* set window height to desired minimal value */
- if (p_wh && curwin->w_height < p_wh)
- win_setheight((int)p_wh);
- }
-
- /*
- * allocate a window structure and link it in the window list
- */
- WIN *
- win_alloc(after)
- WIN *after;
- {
- WIN *new;
-
- /*
- * allocate window structure and linesizes arrays
- */
- new = (WIN *)alloc((unsigned)sizeof(WIN));
- if (new)
- {
- /*
- * most stucture members have to be zero
- */
- memset((char *)new, 0, sizeof(WIN));
- /*
- * link the window in the window list
- */
- win_append(after, new);
-
- win_alloc_lsize(new);
-
- /* position the display and the cursor at the top of the file. */
- new->w_topline = 1;
- new->w_cursor.lnum = 1;
- }
- return new;
- }
-
- /*
- * remove window 'wp' from the window list and free the structure
- */
- void
- win_free(wp)
- WIN *wp;
- {
- if (prevwin == wp)
- prevwin = NULL;
- win_free_lsize(wp);
- win_remove(wp);
- free(wp);
- }
-
- static void
- win_append(after, wp)
- WIN *after, *wp;
- {
- WIN *before;
-
- if (after == NULL) /* after NULL is in front of the first */
- before = firstwin;
- else
- before = after->w_next;
-
- wp->w_next = before;
- wp->w_prev = after;
- if (after == NULL)
- firstwin = wp;
- else
- after->w_next = wp;
- if (before == NULL)
- lastwin = wp;
- else
- before->w_prev = wp;
- }
-
- /*
- * remove window from the window list
- */
- static void
- win_remove(wp)
- WIN *wp;
- {
- if (wp->w_prev)
- wp->w_prev->w_next = wp->w_next;
- else
- firstwin = wp->w_next;
- if (wp->w_next)
- wp->w_next->w_prev = wp->w_prev;
- else
- lastwin = wp->w_prev;
- }
-
- /*
- * allocate lsize arrays for a window
- * return FAIL for failure, OK for success
- */
- int
- win_alloc_lsize(wp)
- WIN *wp;
- {
- wp->w_lsize_valid = 0;
- wp->w_lsize_lnum = (linenr_t *) malloc((size_t) (Rows * sizeof(linenr_t)));
- wp->w_lsize = (char_u *)malloc((size_t) Rows);
- if (wp->w_lsize_lnum == NULL || wp->w_lsize == NULL)
- {
- win_free_lsize(wp); /* one of the two may have worked */
- wp->w_lsize_lnum = NULL;
- wp->w_lsize = NULL;
- return FAIL;
- }
- return OK;
- }
-
- /*
- * free lsize arrays for a window
- */
- void
- win_free_lsize(wp)
- WIN *wp;
- {
- free(wp->w_lsize_lnum);
- free(wp->w_lsize);
- }
-
- /*
- * call this fuction whenever Rows changes value
- */
- void
- screen_new_rows()
- {
- WIN *wp;
- int extra_lines;
-
- if (firstwin == NULL) /* not initialized yet */
- return;
- /*
- * the number of extra lines is the difference between the position where
- * the command line should be and where it is now
- */
- compute_cmdrow();
- extra_lines = Rows - p_ch - cmdline_row;
- if (extra_lines < 0) /* reduce windows height */
- {
- for (wp = lastwin; wp; wp = wp->w_prev)
- {
- if (wp->w_height - MIN_ROWS < -extra_lines)
- {
- extra_lines += wp->w_height - MIN_ROWS;
- wp->w_height = MIN_ROWS;
- win_comp_scroll(wp);
- }
- else
- {
- wp->w_height += extra_lines;
- win_comp_scroll(wp);
- break;
- }
- }
- (void)win_comp_pos(); /* compute w_winpos */
- }
- else if (extra_lines > 0) /* increase height of last window */
- {
- lastwin->w_height += extra_lines;
- win_comp_scroll(lastwin);
- }
-
- compute_cmdrow();
- }
-
- /*
- * update the w_winpos field for all windows
- * returns the row just after the last window
- */
- static int
- win_comp_pos()
- {
- WIN *wp;
- int row;
-
- row = 0;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- {
- if (wp->w_winpos != row) /* if position changes, redraw */
- {
- wp->w_winpos = row;
- wp->w_redr_type = NOT_VALID;
- wp->w_redr_status = TRUE;
- }
- row += wp->w_height + wp->w_status_height;
- }
- return row;
- }
-
- /*
- * set current window height
- */
- void
- win_setheight(height)
- int height;
- {
- WIN *wp;
- int room; /* total number of lines available */
- int take; /* number of lines taken from other windows */
- int room_cmdline; /* lines available from cmdline */
- int row;
-
- if (height < MIN_ROWS) /* need at least some lines */
- height = MIN_ROWS;
- /*
- * compute the room we have from all the windows
- */
- room = MIN_ROWS; /* count the MIN_ROWS for the current window */
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- room += wp->w_height - MIN_ROWS;
- /*
- * compute the room available from the command line
- */
- room_cmdline = Rows - p_ch - cmdline_row;
- /*
- * limit new height to the room available
- */
- if (height > room + room_cmdline) /* can't make it that large */
- height = room + room_cmdline; /* use all available room */
- /*
- * compute the number of lines we will take from the windows (can be negative)
- */
- take = height - curwin->w_height;
- if (take == 0) /* no change, nothing to do */
- return;
-
- if (take > 0)
- {
- take -= room_cmdline; /* use lines from cmdline first */
- if (take < 0)
- take = 0;
- }
- /*
- * set the current window to the new height
- */
- curwin->w_height = height;
- win_comp_scroll(curwin);
- /*
- * take lines from the windows below the current window
- */
- for (wp = curwin->w_next; wp != NULL && take != 0; wp = wp->w_next)
- {
- if (wp->w_height - take < MIN_ROWS)
- {
- take -= wp->w_height - MIN_ROWS;
- wp->w_height = MIN_ROWS;
- }
- else
- {
- wp->w_height -= take;
- take = 0;
- }
- win_comp_scroll(wp); /* recompute p_scroll */
- wp->w_redr_type = NOT_VALID; /* need to redraw this window */
- wp->w_redr_status = TRUE;
- }
- /*
- * take lines from the windows above the current window
- */
- for (wp = curwin->w_prev; wp != NULL && take != 0; wp = wp->w_prev)
- {
- if (wp->w_height - take < MIN_ROWS)
- {
- take -= wp->w_height - MIN_ROWS;
- wp->w_height = MIN_ROWS;
- }
- else
- {
- wp->w_height -= take;
- take = 0;
- }
- win_comp_scroll(wp); /* recompute p_scroll */
- wp->w_redr_type = NOT_VALID; /* need to redraw this window */
- wp->w_redr_status = TRUE;
- }
-
- /* recompute the window positions */
- row = win_comp_pos();
-
- /*
- * If there is extra space created between the last window and the command line,
- * clear it.
- */
- screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ');
- cmdline_row = row;
-
- updateScreen(NOT_VALID);
- }
-
- void
- win_comp_scroll(wp)
- WIN *wp;
- {
- wp->w_p_scroll = (wp->w_height >> 1);
- if (wp->w_p_scroll == 0)
- wp->w_p_scroll = 1;
- }
-
- /*
- * command_height: called whenever p_ch has been changed
- */
- void
- command_height()
- {
- int current;
-
- current = Rows - cmdline_row;
- if (current > p_ch) /* p_ch got smaller */
- lastwin->w_height += current - p_ch;
- else /* p_ch got bigger */
- {
- if (lastwin->w_height - (p_ch - current) < MIN_ROWS)
- {
- emsg(e_noroom);
- p_ch = lastwin->w_height - MIN_ROWS + current;
- }
- lastwin->w_height -= p_ch - current;
- /* clear the lines added to cmdline */
- screen_fill((int)(Rows - p_ch), (int)Rows, 0, (int)Columns, ' ', ' ');
- }
- win_comp_scroll(lastwin);
- cmdline_row = Rows - p_ch;
- lastwin->w_redr_type = NOT_VALID;
- lastwin->w_redr_status = TRUE;
- redraw_cmdline = TRUE;
- }
-
- void
- last_status()
- {
- if (lastwin->w_status_height)
- {
- /* remove status line */
- if (p_ls == 0 || (p_ls == 1 && firstwin == lastwin))
- {
- lastwin->w_status_height = 0;
- lastwin->w_height++;
- win_comp_scroll(lastwin);
- lastwin->w_redr_status = TRUE;
- }
- }
- else
- {
- /* add status line */
- if (p_ls == 2 || (p_ls == 1 && firstwin != lastwin))
- {
- if (lastwin->w_height <= MIN_ROWS) /* can't do it */
- emsg(e_noroom);
- else
- {
- lastwin->w_status_height = 1;
- lastwin->w_height--;
- win_comp_scroll(lastwin);
- lastwin->w_redr_status = TRUE;
- }
- }
- }
- }
-
- /*
- * file_name_at_cursor()
- *
- * Return the name of the file under (or to the right of) the cursor. The
- * p_path variable is searched if the file name does not start with '/'.
- * The string returned has been alloc'ed and should be freed by the caller.
- * NULL is returned if the file name or file is not found.
- */
- char_u *
- file_name_at_cursor()
- {
- char_u *ptr;
- char_u *dir;
- char_u *file_name;
- char_u save_char;
- int col;
- int len;
-
- /* characters in a file name besides alfa-num */
- #ifdef UNIX
- char_u *file_chars = (char_u *)"/.-_+,~$";
- #endif
- #ifdef AMIGA
- char_u *file_chars = (char_u *)"/.-_+,$:";
- #endif
- #ifdef MSDOS
- char_u *file_chars = (char_u *)"/.-_+,$\\:";
- #endif
-
- ptr = ml_get(curwin->w_cursor.lnum);
- col = curwin->w_cursor.col;
-
- /* search forward for what could be the start of a file name */
- while (!isalnum((char) ptr[col]) && STRCHR(file_chars, ptr[col]) == NULL)
- ++col;
- if (ptr[col] == NUL) /* nothing found */
- return NULL;
-
- /* search backward for char that cannot be in a file name */
- while (col >= 0 &&
- (isalnum((char) ptr[col]) || STRCHR(file_chars, ptr[col]) != NULL))
- --col;
- ptr += col + 1;
- col = 0;
-
- /* search forward for a char that cannot be in a file name */
- while (ptr[col] != NUL
- && (isalnum((char) ptr[col]) || STRCHR(file_chars, ptr[col]) != NULL))
- ++col;
-
- /* copy file name into NameBuff, expanding environment variables */
- save_char = ptr[col];
- ptr[col] = NUL;
- expand_env(ptr, NameBuff, MAXPATHL);
- ptr[col] = save_char;
-
- if (isFullName(NameBuff)) /* absolute path */
- {
- if ((file_name = strsave(NameBuff)) == NULL)
- return NULL;
- if (getperm(file_name) >= 0)
- return file_name;
- }
- else /* relative path, use 'path' option */
- {
- if ((file_name = alloc((int)(STRLEN(p_path) + STRLEN(NameBuff) + 2))) == NULL)
- return NULL;
- dir = p_path;
- for (;;)
- {
- skipspace(&dir);
- for (len = 0; dir[len] != NUL && dir[len] != ' '; len++)
- ;
- if (len == 0)
- break;
- if (len == 1 && dir[0] == '.') /* current dir */
- STRCPY(file_name, NameBuff);
- else
- {
- STRNCPY(file_name, dir, (size_t)len);
- #ifdef AMIGA /* Amiga doesn't like c:/file */
- if (file_name[len - 1] != ':')
- #endif
- file_name[len] = '/';
- STRCPY(file_name + len + 1, NameBuff);
- }
- if (getperm(file_name) >= 0)
- return file_name;
- dir += len;
- }
- }
- free(file_name); /* file doesn't exist */
- return NULL;
- }
-