window.c
资源名称:vim53src.zip [点击查看]
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:51k
源码类别:
编辑器/阅读器
开发平台:
DOS
- /* vi:set ts=8 sts=4 sw=4:
- *
- * VIM - Vi IMproved by Bram Moolenaar
- *
- * Do ":help uganda" in Vim to read a list of people who contributed.
- * Do ":help credits" in Vim to see a list of people who contributed.
- */
- #include "vim.h"
- #ifdef FILE_IN_PATH
- static char_u *find_file_in_path __ARGS((char_u *ptr, int len, int options, long count));
- static char_u *find_file_in_wildcard_path __ARGS((char_u *path_so_far, char_u *wildcards, int level, long *countptr));
- static int path_is_url __ARGS((char_u *p));
- #endif
- static void reset_VIsual __ARGS((void));
- static int win_comp_pos __ARGS((void));
- static void win_exchange __ARGS((long));
- static void win_rotate __ARGS((int, int));
- static void win_goto __ARGS((WIN *wp));
- static void win_append __ARGS((WIN *, WIN *));
- static void win_remove __ARGS((WIN *));
- static void win_new_height __ARGS((WIN *, int));
- static WIN *prevwin = NULL; /* previous window */
- #define URL_SLASH 1 /* path_is_url() has found "://" */
- #define URL_BACKSLASH 2 /* path_is_url() has found ":\" */
- /*
- * all CTRL-W window commands are handled here, called from normal_cmd().
- */
- void
- do_window(nchar, Prenum)
- int nchar;
- long Prenum;
- {
- long Prenum1;
- WIN *wp;
- int xchar;
- #if defined(FILE_IN_PATH) || defined(FIND_IN_PATH)
- char_u *ptr;
- #endif
- #ifdef FIND_IN_PATH
- int type = FIND_DEFINE;
- int len;
- #endif
- if (Prenum == 0)
- Prenum1 = 1;
- else
- Prenum1 = Prenum;
- switch (nchar)
- {
- /* split current window in two parts */
- case 'S':
- case Ctrl('S'):
- case 's': reset_VIsual(); /* stop Visual mode */
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- win_split((int)Prenum, TRUE, FALSE);
- break;
- /* split current window and edit alternate file */
- case K_CCIRCM:
- case '^':
- reset_VIsual(); /* stop Visual mode */
- stuffReadbuff((char_u *)":split #");
- if (Prenum)
- stuffnumReadbuff(Prenum); /* buffer number */
- stuffcharReadbuff('n');
- break;
- /* open new window */
- case Ctrl('N'):
- case 'n': reset_VIsual(); /* stop Visual mode */
- stuffcharReadbuff(':');
- if (Prenum)
- stuffnumReadbuff(Prenum); /* window height */
- stuffReadbuff((char_u *)"newn"); /* it is ex_docmd.c */
- break;
- /* quit current window */
- case Ctrl('Q'):
- case 'q': reset_VIsual(); /* stop Visual mode */
- stuffReadbuff((char_u *)":quitn"); /* it is ex_docmd.c */
- break;
- /* close current window */
- case Ctrl('C'):
- case 'c': reset_VIsual(); /* stop Visual mode */
- stuffReadbuff((char_u *)":closen"); /* it is ex_docmd.c */
- break;
- /* close all but current window */
- case Ctrl('O'):
- case 'o': reset_VIsual(); /* stop Visual mode */
- stuffReadbuff((char_u *)":onlyn"); /* it is ex_docmd.c */
- break;
- /* cursor to next window */
- case 'j':
- case K_DOWN:
- case Ctrl('J'):
- for (wp = curwin; wp->w_next != NULL && Prenum1-- > 0;
- wp = wp->w_next)
- ;
- win_goto(wp);
- break;
- /* cursor to next window with wrap around */
- case Ctrl('W'):
- case 'w':
- /* cursor to previous window with wrap around */
- case 'W':
- if (lastwin == firstwin) /* just one window */
- beep_flush();
- else
- {
- if (Prenum) /* go to specified window */
- {
- for (wp = firstwin; --Prenum > 0; )
- {
- if (wp->w_next == NULL)
- break;
- else
- wp = wp->w_next;
- }
- }
- else
- {
- if (nchar == 'W') /* go to previous window */
- {
- wp = curwin->w_prev;
- if (wp == NULL)
- wp = lastwin; /* wrap around */
- }
- else /* go to next window */
- {
- wp = curwin->w_next;
- if (wp == NULL)
- wp = firstwin; /* wrap around */
- }
- }
- win_goto(wp);
- }
- break;
- /* cursor to window above */
- case 'k':
- case K_UP:
- case Ctrl('K'):
- for (wp = curwin; wp->w_prev != NULL && Prenum1-- > 0;
- wp = wp->w_prev)
- ;
- win_goto(wp);
- break;
- /* cursor to top window */
- case 't':
- case Ctrl('T'):
- wp = firstwin;
- win_goto(wp);
- break;
- /* cursor to bottom window */
- case 'b':
- case Ctrl('B'):
- wp = lastwin;
- win_goto(wp);
- break;
- /* cursor to last accessed (previous) window */
- case 'p':
- case Ctrl('P'):
- if (prevwin == NULL)
- beep_flush();
- else
- {
- wp = prevwin;
- win_goto(wp);
- }
- break;
- /* exchange current and next window */
- case 'x':
- case Ctrl('X'):
- win_exchange(Prenum);
- break;
- /* rotate windows downwards */
- case Ctrl('R'):
- case 'r': reset_VIsual(); /* stop Visual mode */
- win_rotate(FALSE, (int)Prenum1); /* downwards */
- break;
- /* rotate windows upwards */
- case 'R': reset_VIsual(); /* stop Visual mode */
- win_rotate(TRUE, (int)Prenum1); /* upwards */
- break;
- /* make all windows the same height */
- case '=':
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- win_equal(NULL, TRUE);
- break;
- /* increase current window height */
- case '+':
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- win_setheight(curwin->w_height + (int)Prenum1);
- break;
- /* decrease current window height */
- case '-':
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- win_setheight(curwin->w_height - (int)Prenum1);
- break;
- /* set current window height */
- case Ctrl('_'):
- case '_':
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- win_setheight(Prenum ? (int)Prenum : 9999);
- break;
- /* jump to tag and split window if tag exists */
- case ']':
- case Ctrl(']'):
- reset_VIsual(); /* stop Visual mode */
- if (Prenum)
- postponed_split = Prenum;
- else
- postponed_split = -1;
- stuffcharReadbuff(Ctrl(']'));
- break;
- #ifdef FILE_IN_PATH
- /* edit file name under cursor in a new window */
- case 'f':
- case Ctrl('F'):
- reset_VIsual(); /* stop Visual mode */
- ptr = file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP,
- Prenum1);
- if (ptr != NULL)
- {
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- setpcmark();
- if (win_split(0, FALSE, FALSE) == OK)
- (void)do_ecmd(0, ptr, NULL, NULL, (linenr_t)0,
- ECMD_HIDE);
- vim_free(ptr);
- }
- break;
- #endif
- #ifdef FIND_IN_PATH
- /* Go to the first occurence of the identifier under cursor along path in a
- * new window -- webb
- */
- case 'i': /* Go to any match */
- case Ctrl('I'):
- type = FIND_ANY;
- /* FALLTHROUGH */
- case 'd': /* Go to definition, using p_def */
- case Ctrl('D'):
- if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
- break;
- find_pattern_in_path(ptr, 0, len, TRUE,
- Prenum == 0 ? TRUE : FALSE, type,
- Prenum1, ACTION_SPLIT, (linenr_t)1, (linenr_t)MAXLNUM);
- curwin->w_set_curswant = TRUE;
- break;
- #endif
- /* CTRL-W g extended commands */
- case 'g':
- #ifdef USE_GUI_WIN32
- dont_scroll = TRUE; /* disallow scrolling here */
- #endif
- ++no_mapping;
- ++allow_keys; /* no mapping for xchar, but allow key codes */
- xchar = vgetc();
- #ifdef HAVE_LANGMAP
- LANGMAP_ADJUST(xchar, TRUE);
- #endif
- --no_mapping;
- --allow_keys;
- #ifdef SHOWCMD
- (void)add_to_showcmd(xchar);
- #endif
- switch (xchar)
- {
- case ']':
- case Ctrl(']'):
- reset_VIsual(); /* stop Visual mode */
- if (Prenum)
- postponed_split = Prenum;
- else
- postponed_split = -1;
- stuffcharReadbuff('g');
- stuffcharReadbuff(xchar);
- break;
- default:
- beep_flush();
- break;
- }
- break;
- default: beep_flush();
- break;
- }
- }
- static void
- reset_VIsual()
- {
- if (VIsual_active)
- {
- end_visual_mode();
- update_curbuf(NOT_VALID); /* delete the inversion */
- }
- VIsual_reselect = FALSE;
- }
- /*
- * 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, req_room)
- int new_height;
- int redraw;
- int req_room; /* require enough room for new window */
- {
- WIN *wp;
- int i;
- int need_status;
- int do_equal = (p_ea && new_height == 0);
- int needed;
- int available;
- int curwin_height;
- /* 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 * p_wmh + STATUS_HEIGHT + need_status;
- if (req_room)
- needed += p_wh - p_wmh;
- if (p_ea)
- {
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp != curwin)
- {
- available += wp->w_height;
- needed += p_wmh;
- }
- }
- if (available < needed)
- {
- EMSG(e_noroom);
- return FAIL;
- }
- curwin_height = curwin->w_height;
- if (need_status)
- {
- curwin->w_status_height = STATUS_HEIGHT;
- curwin_height -= STATUS_HEIGHT;
- }
- if (new_height == 0)
- new_height = curwin_height / 2;
- if (new_height > curwin_height - p_wmh - STATUS_HEIGHT)
- new_height = curwin_height - p_wmh - STATUS_HEIGHT;
- if (new_height < p_wmh)
- new_height = p_wmh;
- /* if it doesn't fit in the current window, need win_equal() */
- if (curwin_height - new_height - STATUS_HEIGHT < p_wmh)
- 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
- */
- win_new_height(wp, new_height);
- win_new_height(curwin, curwin_height - (new_height + STATUS_HEIGHT));
- 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_valid = 0;
- wp->w_curswant = curwin->w_curswant;
- wp->w_set_curswant = curwin->w_set_curswant;
- wp->w_topline = curwin->w_topline;
- wp->w_leftcol = curwin->w_leftcol;
- wp->w_pcmark = curwin->w_pcmark;
- wp->w_prev_pcmark = curwin->w_prev_pcmark;
- wp->w_alt_fnum = curwin->w_alt_fnum;
- wp->w_fraction = curwin->w_fraction;
- wp->w_prev_fraction_row = curwin->w_prev_fraction_row;
- 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 = vim_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;
- if (need_status)
- {
- msg_row = Rows - 1;
- msg_col = sc_col;
- msg_clr_eos(); /* Old command/ruler may still be there -- webb */
- comp_col();
- msg_row = Rows - 1;
- msg_col = 0; /* put position back at start of line */
- }
- /*
- * make the new window the current window and redraw
- */
- if (do_equal)
- win_equal(wp, FALSE);
- win_enter(wp, FALSE);
- if (redraw)
- update_screen(NOT_VALID);
- else
- redraw_later(NOT_VALID);
- return OK;
- }
- /*
- * Check if "win" is a pointer to an existing window.
- */
- int
- win_valid(win)
- WIN *win;
- {
- WIN *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (wp == win)
- return TRUE;
- return FALSE;
- }
- /*
- * Return the number of windows.
- */
- int
- win_count()
- {
- WIN *wp;
- int count = 0;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- ++count;
- return count;
- }
- /*
- * Make 'count' windows on the screen.
- * Return actual number of windows on the screen.
- * Must be called when there is just one window, filling the whole screen
- * (excluding the command line).
- */
- int
- make_windows(count)
- int count;
- {
- int maxcount;
- int todo;
- int p_sb_save;
- /*
- * Each window needs at least 'winminheight' lines and a status line.
- * Add 4 lines for one window, otherwise we may end up with all zero-line
- * windows. Use value of 'winheight' if it is set
- */
- maxcount = (curwin->w_height + curwin->w_status_height
- - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
- if (maxcount < 2)
- maxcount = 2;
- 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;
- win_new_height(curwin, curwin->w_height - STATUS_HEIGHT);
- }
- #ifdef AUTOCMD
- /*
- * Don't execute autocommands while creating the windows. Must do that
- * when putting the buffers in the windows.
- */
- ++autocmd_busy;
- #endif
- /*
- * set 'splitbelow' off for a moment, don't want 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(curwin->w_height - (curwin->w_height - todo
- * STATUS_HEIGHT) / (todo + 1) - STATUS_HEIGHT,
- FALSE, FALSE) == FAIL)
- break;
- p_sb = p_sb_save;
- #ifdef AUTOCMD
- --autocmd_busy;
- #endif
- /* 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_flush();
- return;
- }
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- /*
- * 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);
- update_screen(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_flush();
- return;
- }
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- 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();
- }
- update_screen(CLEAR);
- }
- /*
- * Move window "win1" to below "win2" and make "win1" the current window.
- */
- void
- win_move_after(win1, win2)
- WIN *win1, *win2;
- {
- int height;
- /* check if the arguments are reasonable */
- if (win1 == win2)
- return;
- /* check if there is something to do */
- if (win2->w_next != win1)
- {
- /* may need move the status line of the last window */
- if (win1 == lastwin)
- {
- height = win1->w_prev->w_status_height;
- win1->w_prev->w_status_height = win1->w_status_height;
- win1->w_status_height = height;
- }
- else if (win2 == lastwin)
- {
- height = win1->w_status_height;
- win1->w_status_height = win2->w_status_height;
- win2->w_status_height = height;
- }
- win_remove(win1);
- win_append(win2, win1);
- (void)win_comp_pos(); /* recompute w_winpos for all windows */
- redraw_later(NOT_VALID);
- }
- win_enter(win1, FALSE);
- }
- /*
- * Make all windows the same height.
- * 'next_curwin' will soon be the current window, make sure it has enough
- * rows.
- */
- 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 - p_wmh;
- wincount++;
- }
- /*
- * If next_curwin given and 'winheight' set, make next_curwin p_wh lines.
- */
- less = 0;
- if (next_curwin != NULL)
- {
- if (p_wh - p_wmh > total) /* all lines go to current window */
- less = total;
- else
- {
- less = p_wh - p_wmh - total / wincount;
- if (less < 0)
- 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 - p_wmh;
- if (temp > total)
- temp = total;
- }
- else
- temp = (total - less + ((unsigned)wincount >> 1)) / wincount;
- new_height = p_wmh + 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;
- win_new_height(wp, new_height);
- total -= temp;
- --wincount;
- winpos += wp->w_height + wp->w_status_height;
- }
- if (redraw)
- must_redraw = CLEAR;
- }
- /*
- * close all windows for buffer 'buf'
- */
- void
- close_windows(buf)
- BUF *buf;
- {
- WIN *win;
- ++RedrawingDisabled;
- for (win = firstwin; win != NULL && lastwin != firstwin; )
- {
- if (win->w_buffer == buf)
- {
- close_window(win, FALSE);
- win = firstwin; /* go back to the start */
- }
- else
- win = win->w_next;
- }
- --RedrawingDisabled;
- }
- /*
- * close window "win"
- * If "free_buf" is TRUE related buffer may be freed.
- *
- * called by :quit, :close, :xit, :wq and findtag()
- */
- void
- close_window(win, free_buf)
- WIN *win;
- int free_buf;
- {
- WIN *wp;
- #ifdef AUTOCMD
- int other_buffer = FALSE;
- #endif
- if (lastwin == firstwin)
- {
- EMSG("Cannot close last window");
- return;
- }
- #ifdef AUTOCMD
- if (win == curwin)
- {
- /*
- * Guess which window is going to be the new current window.
- * This may change because of the autocommands (sigh).
- */
- if ((!p_sb && win->w_next != NULL) || win->w_prev == NULL)
- wp = win->w_next;
- else
- wp = win->w_prev;
- /*
- * Be careful: If autocommands delete the window, return now.
- */
- if (wp->w_buffer != curbuf)
- {
- other_buffer = TRUE;
- apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(win))
- return;
- }
- apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(win))
- return;
- }
- #endif
- /*
- * Remove the window.
- * if 'splitbelow' the free space goes to the window above it.
- * if 'nosplitbelow' the free space goes to the window below it.
- * This makes opening a window and closing it immediately keep the same window
- * layout.
- */
- /* freed space goes to next window */
- if ((!p_sb && win->w_next != NULL) || win->w_prev == NULL)
- {
- wp = win->w_next;
- wp->w_winpos = win->w_winpos;
- }
- else /* freed space goes to previous window */
- wp = win->w_prev;
- win_new_height(wp, wp->w_height + win->w_height + win->w_status_height);
- /*
- * Close the link to the buffer.
- */
- close_buffer(win, win->w_buffer, free_buf, FALSE);
- win_free(win);
- if (win == curwin)
- curwin = NULL;
- if (p_ea)
- win_equal(wp, FALSE);
- if (curwin == NULL)
- {
- win_enter(wp, FALSE);
- #ifdef AUTOCMD
- if (other_buffer)
- /* careful: after this wp and win may be invalid! */
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
- #endif
- }
- /*
- * 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)))
- {
- win_new_height(lastwin, lastwin->w_height + lastwin->w_status_height);
- lastwin->w_status_height = 0;
- comp_col();
- }
- update_screen(NOT_VALID);
- }
- /*
- * Close all windows except current one.
- * Buffers in the other windows become hidden if 'hidden' is set, or '!' is
- * used and the buffer was modified.
- *
- * Used by ":bdel" and ":only".
- */
- void
- close_others(message, forceit)
- int message;
- int forceit; /* always hide all other windows */
- {
- WIN *wp;
- WIN *nextwp;
- if (lastwin == firstwin)
- {
- if (message
- #ifdef AUTOCMD
- && !autocmd_busy
- #endif
- )
- MSG("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;
- /* Check if it's allowed to abandon this window */
- if (!can_abandon(wp->w_buffer, forceit))
- continue;
- /* Close the link to the buffer. */
- close_buffer(wp, wp->w_buffer,
- !p_hid && !buf_changed(wp->w_buffer), FALSE);
- /* Remove the window. All lines go to previous or next window. */
- if (wp->w_prev != NULL)
- win_new_height(wp->w_prev,
- wp->w_prev->w_height + wp->w_height + wp->w_status_height);
- else
- {
- win_new_height(wp->w_next,
- wp->w_next->w_height + wp->w_height + wp->w_status_height);
- wp->w_next->w_winpos = wp->w_winpos;
- }
- win_free(wp);
- }
- /*
- * If current window has a status line and we don't want one,
- * remove the status line.
- */
- if (lastwin != firstwin)
- EMSG("Other window contains changes");
- else if (curwin->w_status_height && p_ls != 2)
- {
- win_new_height(curwin, curwin->w_height + curwin->w_status_height);
- curwin->w_status_height = 0;
- comp_col();
- }
- if (message)
- update_screen(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;
- #ifdef FKMAP
- if (curwin->w_p_rl)
- wp->w_p_pers = W_CONV + W_R_L;
- else
- wp->w_p_pers = W_CONV;
- #endif
- }
- /*
- * Go to another window.
- * When jumping to another buffer, stop visual mode. Do this before
- * changing windows so we can yank the selection into the '*' register.
- */
- static void
- win_goto(wp)
- WIN *wp;
- {
- if (wp->w_buffer != curbuf && VIsual_active)
- {
- end_visual_mode();
- redraw_curbuf_later(NOT_VALID);
- }
- VIsual_reselect = FALSE;
- #ifdef USE_GUI
- need_mouse_correct = TRUE;
- #endif
- win_enter(wp, TRUE);
- }
- /*
- * Go to window nr "winnr" (counting top to bottom).
- */
- WIN *
- win_goto_nr(winnr)
- int winnr;
- {
- WIN *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (--winnr == 0)
- break;
- return wp;
- }
- /*
- * Make window wp the current window.
- * Can be called when curwin == NULL, if curwin already has been closed.
- */
- void
- win_enter(wp, undo_sync)
- WIN *wp;
- int undo_sync;
- {
- #ifdef AUTOCMD
- int other_buffer = FALSE;
- #endif
- if (wp == curwin) /* nothing to do */
- return;
- #ifdef AUTOCMD
- if (curwin != NULL)
- {
- /*
- * Be careful: If autocommands delete the window, return now.
- */
- if (wp->w_buffer != curbuf)
- {
- apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
- other_buffer = TRUE;
- if (!win_valid(wp))
- return;
- }
- apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(wp))
- return;
- }
- #endif
- /* sync undo before leaving the current buffer */
- if (undo_sync && curbuf != wp->w_buffer)
- u_sync();
- /* may have to copy the buffer options when 'cpo' contains 'S' */
- if (wp->w_buffer != curbuf)
- buf_copy_options(curbuf, wp->w_buffer, BCO_ENTER | BCO_NOHELP);
- if (curwin != NULL)
- {
- prevwin = curwin; /* remember for CTRL-W p */
- curwin->w_redr_status = TRUE;
- }
- curwin = wp;
- curbuf = wp->w_buffer;
- adjust_cursor();
- changed_line_abv_curs(); /* assume cursor position needs updating */
- #ifdef AUTOCMD
- apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
- if (other_buffer)
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
- #endif
- maketitle();
- curwin->w_redr_status = TRUE;
- /* set window height to desired minimal value */
- if (curwin->w_height < p_wh)
- win_setheight((int)p_wh);
- #ifdef USE_MOUSE
- setmouse(); /* in case jumped to/from help buffer */
- #endif
- }
- /*
- * allocate a window structure and link it in the window list
- */
- WIN *
- win_alloc(after)
- WIN *after;
- {
- WIN *newwin;
- /*
- * allocate window structure and linesizes arrays
- */
- newwin = (WIN *)alloc_clear((unsigned)sizeof(WIN));
- if (newwin != NULL && win_alloc_lsize(newwin) == FAIL)
- {
- vim_free(newwin);
- newwin = NULL;
- }
- if (newwin != NULL)
- {
- /*
- * link the window in the window list
- */
- win_append(after, newwin);
- /* position the display and the cursor at the top of the file. */
- newwin->w_topline = 1;
- newwin->w_botline = 2;
- newwin->w_cursor.lnum = 1;
- /* We won't calculate w_fraction until resizing the window */
- newwin->w_fraction = 0;
- newwin->w_prev_fraction_row = -1;
- #ifdef USE_GUI
- if (gui.in_use)
- {
- gui_create_scrollbar(&newwin->w_scrollbars[SBAR_LEFT], newwin);
- gui_create_scrollbar(&newwin->w_scrollbars[SBAR_RIGHT], newwin);
- }
- #endif
- #ifdef WANT_EVAL
- var_init(&newwin->w_vars); /* init internal variables */
- #endif
- }
- return newwin;
- }
- /*
- * remove window 'wp' from the window list and free the structure
- */
- void
- win_free(wp)
- WIN *wp;
- {
- int i;
- #ifdef HAVE_PERL_INTERP
- perl_win_free(wp);
- #endif
- #ifdef HAVE_PYTHON
- python_window_free(wp);
- #endif
- #ifdef HAVE_TCL
- tcl_window_free(wp);
- #endif
- #ifdef WANT_EVAL
- var_clear(&wp->w_vars); /* free all internal variables */
- #endif
- if (prevwin == wp)
- prevwin = NULL;
- win_free_lsize(wp);
- for (i = 0; i < wp->w_tagstacklen; ++i)
- vim_free(wp->w_tagstack[i].tagname);
- #ifdef USE_GUI
- if (gui.in_use)
- {
- gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_LEFT]);
- gui_mch_destroy_scrollbar(&wp->w_scrollbars[SBAR_RIGHT]);
- }
- #endif /* USE_GUI */
- win_remove(wp);
- vim_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 *)alloc((unsigned)(Rows * sizeof(linenr_t)));
- wp->w_lsize = alloc((unsigned)Rows);
- if (wp->w_lsize_lnum == NULL || wp->w_lsize == NULL)
- {
- win_free_lsize(wp); /* one of the two may have worked */
- return FAIL;
- }
- return OK;
- }
- /*
- * free lsize arrays for a window
- */
- void
- win_free_lsize(wp)
- WIN *wp;
- {
- vim_free(wp->w_lsize_lnum);
- vim_free(wp->w_lsize);
- wp->w_lsize_lnum = NULL;
- wp->w_lsize = NULL;
- }
- /*
- * 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
- */
- extra_lines = Rows - p_ch -
- (lastwin->w_winpos + lastwin->w_height + lastwin->w_status_height);
- if (extra_lines < 0) /* reduce windows height */
- {
- for (wp = lastwin; wp; wp = wp->w_prev)
- {
- if (wp->w_height - p_wmh < -extra_lines)
- {
- extra_lines += wp->w_height - p_wmh;
- win_new_height(wp, (int)p_wmh);
- }
- else
- {
- win_new_height(wp, wp->w_height + extra_lines);
- break;
- }
- }
- (void)win_comp_pos(); /* compute w_winpos */
- }
- else if (extra_lines > 0) /* increase height of last window */
- win_new_height(lastwin, lastwin->w_height + extra_lines);
- compute_cmdrow();
- if (p_ea)
- win_equal(curwin, FALSE);
- }
- /*
- * 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;
- int run;
- if (p_wmh == 0)
- {
- /* Always keep current window at least one line high, even when
- * 'winminheight' is zero */
- if (height == 0) /* need at least one line */
- {
- height = 1;
- room = 1;
- }
- else
- room = p_wmh; /* count 'winminheight' for the curr. window */
- }
- else
- {
- if (height < p_wmh) /* need at least some lines */
- height = p_wmh;
- room = p_wmh; /* count 'winminheight' for the curr. window */
- }
- /*
- * compute the room we have from all the windows
- */
- room_cmdline = Rows - p_ch;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- {
- room += wp->w_height - p_wmh;
- room_cmdline -= wp->w_height + wp->w_status_height;
- }
- /*
- * 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
- */
- win_new_height(curwin, height);
- /*
- * First take lines from the windows below the current window.
- * If that is not enough, takes lines from windows above the current window.
- */
- for (run = 0; run < 2; ++run)
- {
- if (run == 0)
- wp = curwin->w_next; /* 1st run: start with next window */
- else
- wp = curwin->w_prev; /* 2nd run: start with prev window */
- while (wp != NULL && take != 0)
- {
- if (wp->w_height - take < p_wmh)
- {
- take -= wp->w_height - p_wmh;
- win_new_height(wp, (int)p_wmh);
- }
- else
- {
- win_new_height(wp, wp->w_height - take);
- take = 0;
- }
- if (run == 0)
- wp = wp->w_next;
- else
- wp = wp->w_prev;
- }
- }
- /* recompute the window positions */
- row = win_comp_pos();
- /*
- * If there is extra space created between the last window and the command line,
- * clear it.
- */
- if (full_screen && msg_scrolled == 0)
- screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
- cmdline_row = row;
- update_screen(NOT_VALID);
- }
- /*
- * Check 'winminheight' for a valid value.
- */
- void
- win_setminheight()
- {
- int room;
- int first = TRUE;
- WIN *wp;
- /* loop until there is a 'winminheight' that is possible */
- while (p_wmh > 0)
- {
- room = -p_wh;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- room += wp->w_height - p_wmh;
- if (room >= 0)
- break;
- --p_wmh;
- if (first)
- {
- EMSG(e_noroom);
- first = FALSE;
- }
- }
- }
- #ifdef USE_MOUSE
- void
- win_drag_status_line(offset)
- int offset;
- {
- WIN *wp;
- int room;
- int row;
- int up; /* if TRUE, drag status line up, otherwise down */
- if (offset < 0)
- {
- up = TRUE;
- offset = -offset;
- }
- else
- up = FALSE;
- if (up) /* drag up */
- {
- if (p_wmh == 0)
- room = -1; /* current window should be at least one line */
- else
- room = 0;
- for (wp = curwin; wp != NULL && room < offset; wp = wp->w_prev)
- room += wp->w_height - p_wmh;
- wp = curwin->w_next; /* put wp at window that grows */
- }
- else /* drag down */
- {
- /*
- * Only dragging the last status line can reduce p_ch.
- */
- room = Rows - cmdline_row;
- if (curwin->w_next == NULL)
- room -= 1;
- else
- room -= p_ch;
- for (wp = curwin->w_next; wp != NULL && room < offset; wp = wp->w_next)
- room += wp->w_height - p_wmh;
- wp = curwin; /* put wp at window that grows */
- }
- if (room < offset) /* Not enough room */
- offset = room; /* Move as far as we can */
- if (offset <= 0)
- return;
- if (wp != NULL) /* grow window wp by offset lines */
- win_new_height(wp, wp->w_height + offset);
- if (up)
- wp = curwin; /* current window gets smaller */
- else
- wp = curwin->w_next; /* next window gets smaller */
- while (wp != NULL && offset > 0)
- {
- if (wp->w_height - offset <= p_wmh)
- {
- offset -= wp->w_height - p_wmh;
- if (wp == curwin && p_wmh == 0)
- {
- win_new_height(wp, 1);
- offset += 1;
- }
- else
- win_new_height(wp, (int)p_wmh);
- }
- else
- {
- win_new_height(wp, wp->w_height - offset);
- offset = 0;
- }
- if (up)
- wp = wp->w_prev;
- else
- wp = wp->w_next;
- }
- row = win_comp_pos();
- screen_fill(row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
- cmdline_row = row;
- p_ch = Rows - cmdline_row;
- update_screen(NOT_VALID);
- showmode();
- }
- #endif /* USE_MOUSE */
- /*
- * Set new window height.
- */
- static void
- win_new_height(wp, height)
- WIN *wp;
- int height;
- {
- linenr_t lnum;
- int sline, line_size;
- #define FRACTION_MULT 16384L
- if (wp->w_wrow != wp->w_prev_fraction_row && wp->w_height > 0)
- wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT
- + FRACTION_MULT / 2) / (long)wp->w_height;
- wp->w_height = height;
- wp->w_skipcol = 0;
- lnum = wp->w_cursor.lnum;
- if (lnum < 1) /* can happen when starting up */
- lnum = 1;
- wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) / FRACTION_MULT;
- line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
- sline = wp->w_wrow - line_size;
- if (sline < 0)
- {
- /*
- * Cursor line would go off top of screen if w_wrow was this high.
- */
- wp->w_wrow = line_size;
- }
- else
- {
- while (sline > 0 && lnum > 1)
- sline -= (line_size = plines_win(wp, --lnum));
- if (sline < 0)
- {
- /*
- * Line we want at top would go off top of screen. Use next line
- * instead.
- */
- lnum++;
- wp->w_wrow -= line_size + sline;
- }
- else if (sline > 0)
- {
- /* First line of file reached, use that as topline. */
- lnum = 1;
- wp->w_wrow -= sline;
- }
- }
- set_topline(wp, lnum);
- if (wp == curwin)
- {
- if (p_so)
- update_topline();
- curs_columns(FALSE); /* validate w_wrow */
- }
- wp->w_prev_fraction_row = wp->w_wrow;
- win_comp_scroll(wp);
- if (wp->w_redr_type < NOT_VALID)
- wp->w_redr_type = NOT_VALID;
- wp->w_redr_status = TRUE;
- invalidate_botline_win(wp);
- }
- void
- win_comp_scroll(wp)
- WIN *wp;
- {
- wp->w_p_scroll = ((unsigned)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(old_p_ch)
- long old_p_ch;
- {
- WIN *wp;
- int h;
- if (!starting)
- {
- cmdline_row = Rows - p_ch;
- if (p_ch > old_p_ch) /* p_ch got bigger */
- {
- for (wp = lastwin; p_ch > old_p_ch; wp = wp->w_prev)
- {
- if (wp == NULL)
- {
- emsg(e_noroom);
- p_ch = old_p_ch;
- break;
- }
- h = wp->w_height - (p_ch - old_p_ch);
- if (p_wmh == 0)
- {
- /* don't make current window zero lines */
- if (wp == curwin && h < 1)
- h = 1;
- }
- else if (h < p_wmh)
- h = p_wmh;
- old_p_ch += wp->w_height - h;
- win_new_height(wp, h);
- }
- win_comp_pos();
- /* clear the lines added to cmdline */
- if (full_screen)
- screen_fill((int)(cmdline_row), (int)Rows, 0,
- (int)Columns, ' ', ' ', 0);
- msg_row = cmdline_row;
- redraw_cmdline = TRUE;
- return;
- }
- if (msg_row < cmdline_row)
- msg_row = cmdline_row;
- redraw_cmdline = TRUE;
- }
- win_new_height(lastwin, (int)(lastwin->w_height + old_p_ch - p_ch));
- }
- void
- last_status()
- {
- WIN *wp;
- if (lastwin->w_status_height)
- {
- /* remove status line */
- if (p_ls == 0 || (p_ls == 1 && firstwin == lastwin))
- {
- win_new_height(lastwin, lastwin->w_height + 1);
- lastwin->w_status_height = 0;
- comp_col();
- }
- }
- else if (p_ls == 2 || (p_ls == 1 && firstwin != lastwin))
- {
- /* go to first window with enough room for a win_new_height(-1) */
- for (wp = lastwin; wp->w_height <= p_wmh; wp = wp->w_prev)
- if (wp == NULL)
- {
- emsg(e_noroom);
- return;
- }
- win_new_height(wp, wp->w_height - 1);
- win_comp_pos();
- lastwin->w_status_height = 1;
- comp_col();
- update_screen(CLEAR);
- }
- }
- #ifdef FILE_IN_PATH
- /*
- * file_name_at_cursor()
- *
- * Return the name of the file under (or to the right of) the cursor.
- *
- * get_file_name_in_path()
- *
- * Return the name of the file at (or to the right of) ptr[col].
- *
- * 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.
- *
- * options:
- * FNAME_MESS give error messages
- * FNAME_EXP expand to path
- * FNAME_HYP check for hypertext link
- */
- char_u *
- file_name_at_cursor(options, count)
- int options;
- long count;
- {
- return get_file_name_in_path(ml_get_curline(),
- curwin->w_cursor.col, options, count);
- }
- char_u *
- get_file_name_in_path(line, col, options, count)
- char_u *line;
- int col;
- int options;
- long count;
- {
- char_u *ptr;
- char_u *file_name;
- int len;
- /*
- * search forward for what could be the start of a file name
- */
- ptr = line + col;
- while (*ptr != NUL && !vim_isfilec(*ptr))
- ++ptr;
- if (*ptr == NUL) /* nothing found */
- {
- if (options & FNAME_MESS)
- EMSG("No file name under cursor");
- return NULL;
- }
- /*
- * search backward for first char of the file name
- */
- while (ptr > line && vim_isfilec(ptr[-1]))
- --ptr;
- /*
- * Go one char back to ":" before "//" even when ':' is not in 'isfname'.
- */
- if ((options & FNAME_HYP) && ptr > line && path_is_url(ptr - 1))
- --ptr;
- /*
- * Search forward for the last char of the file name.
- * Also allow "://" when ':' is not in 'isfname'.
- */
- len = 0;
- while (vim_isfilec(ptr[len])
- || ((options & FNAME_HYP) && path_is_url(ptr + len)))
- ++len;
- if (options & FNAME_HYP)
- {
- /* For hypertext links, ignore the name of the machine.
- * Such a link looks like "type://machine/path". Only "/path" is used.
- * First search for the string "://", then for the extra '/'
- */
- if ((file_name = vim_strchr(ptr, ':')) != NULL &&
- ((path_is_url(file_name) == URL_SLASH &&
- (file_name = vim_strchr(file_name + 3, '/')) != NULL) ||
- (path_is_url(file_name) == URL_BACKSLASH &&
- (file_name = vim_strchr(file_name + 3, '\')) != NULL)) &&
- file_name < ptr + len)
- {
- len -= file_name - ptr;
- ptr = file_name;
- if (ptr[1] == '~') /* skip '/' for /~user/path */
- {
- ++ptr;
- --len;
- }
- }
- }
- if (!(options & FNAME_EXP))
- return vim_strnsave(ptr, len);
- return find_file_in_path(ptr, len, options, count);
- }
- /*
- * Find the file name "ptr[len]" in the path.
- *
- * options:
- * FNAME_MESS give error message when not found
- *
- * Uses NameBuff[]!
- *
- * Returns an allocated string for the file name. NULL for error.
- */
- static char_u *
- find_file_in_path(ptr, len, options, count)
- char_u *ptr; /* file name */
- int len; /* length of file name */
- int options;
- long count; /* use count'th matching file name */
- {
- char_u save_char;
- char_u *file_name;
- char_u *curr_path = NULL;
- char_u *dir;
- int curr_path_len;
- char_u *p;
- char_u *head;
- /* copy file name into NameBuff, expanding environment variables */
- save_char = ptr[len];
- ptr[len] = NUL;
- expand_env(ptr, NameBuff, MAXPATHL);
- ptr[len] = save_char;
- if (mch_isFullName(NameBuff))
- {
- /*
- * Absolute path, no need to use 'path'.
- */
- if ((file_name = vim_strsave(NameBuff)) == NULL)
- return NULL;
- if (mch_getperm(file_name) >= 0)
- return file_name;
- if (options & FNAME_MESS)
- EMSG2("Can't find file "%s"", NameBuff);
- }
- else
- {
- /*
- * Relative path, use 'path' option.
- */
- if (curbuf->b_fname != NULL)
- {
- curr_path = curbuf->b_fname;
- ptr = gettail(curr_path);
- curr_path_len = ptr - curr_path;
- }
- else
- curr_path_len = 0;
- if ((file_name = alloc((int)(curr_path_len + STRLEN(p_path) +
- STRLEN(NameBuff) + 3))) == NULL)
- return NULL;
- for (dir = p_path; *dir && !got_int; )
- {
- len = copy_option_part(&dir, file_name, 31000, " ,");
- /* len == 0 means: use current directory */
- if (len != 0)
- {
- /* Look for file relative to current file */
- if (file_name[0] == '.' && curr_path_len > 0
- && (len == 1 || vim_ispathsep(file_name[1])))
- {
- if (len == 1) /* just a "." */
- len = 0;
- else /* "./path": move "path" */
- {
- len -= 2;
- mch_memmove(file_name + curr_path_len, file_name + 2,
- (size_t)len);
- }
- STRNCPY(file_name, curr_path, curr_path_len);
- len += curr_path_len;
- }
- if (!vim_ispathsep(file_name[len - 1]))
- file_name[len++] = PATHSEP;
- file_name[len] = ' ';
- /*
- * Handle "**" in the path: 'wildcard in path'.
- */
- if (mch_has_wildcard(file_name))
- {
- p = get_past_head(file_name);
- if (p == file_name) /* no absolute file name */
- p = find_file_in_wildcard_path((char_u *)"",
- file_name, 0, &count);
- else /* absolute file name, separate head */
- {
- head = vim_strnsave(file_name,
- (unsigned)(p - file_name));
- if (head != NULL)
- {
- p = find_file_in_wildcard_path(head, p, 0, &count);
- vim_free(head);
- }
- }
- if (p != NULL)
- {
- vim_free(file_name);
- return p;
- }
- continue;
- }
- }
- STRCPY(file_name + len, NameBuff);
- /*
- * Translate names like "src/a/../b/file.c" into "src/b/file.c".
- */
- simplify_filename(file_name);
- if (mch_getperm(file_name) >= 0 && --count == 0)
- return file_name;
- }
- if (options & FNAME_MESS)
- EMSG2("Can't find file "%s" in path", NameBuff);
- }
- /* get here when file doesn't exist */
- vim_free(file_name);
- return NULL;
- }
- /*
- * find_file_in_wildcard_path(): expand path recursively while searching
- * files in path
- *
- * The syntax '**' means the whole subtree.
- * To avoid endless recursion, a counter restricts the depth to 100 levels.
- * In the following pseudo code '+/' will mean '*' followed by '/'
- *
- * in the case of 'set path=,/foo/bar/+/+/,'
- * the function call hierarchy will be
- * find_file_in_wildcard_path("/", "foo/bar/+/+/", NameBuff, 0);
- * find_file_in_wildcard_path("/foo/", "bar/+/+/", NameBuff, 0);
- * find_file_in_wildcard_path("/foo/bar/", "+/+/", NameBuff, 0);
- * which in turn will call
- * find_file_in_wildcard_path("/foo/bar/dir/", "+/", NameBuff, 1);
- * for each directory 'dir' in '/foo/bar/+'. It's the next call,
- * find_file_in_wildcard_path("/foo/bar/dir/dir2/", "", NameBuff, 2);
- * that will try to find the file 'NameBuff' in the given directory.
- *
- * pseudo code:
- *
- * find_file_in_wildcard_path(path_so_far, wildcards, level)
- * {
- * if (level > 100)
- * return NULL;
- *
- * file_name = path_so_far + first_segment(wildcards);
- * rest_of_wildcards = all_but_first_segment(wildcards);
- *
- * result = expand(file_name);
- *
- * if (!rest_of_wildcards) {
- * foreach_path_in(result) {
- * if (exists&readable(path + NameBuff))
- * return path+NameBuff;
- * }
- * } else {
- * foreach_path_in(result) {
- * c = find_file_in_wildcard_path(path, rest_of_wildcards, level+1);
- * if (c)
- * return c;
- * }
- * }
- * if (infinite_recursion(wildcards)) {
- * foreach_path_in(result) {
- * c = find_file_in_wildcard_path(path, wildcards, level+1);
- * if (c)
- * return c;
- * }
- * }
- * return NULL;
- * }
- */
- static char_u *
- find_file_in_wildcard_path(path_so_far, wildcards, level, countptr)
- char_u *path_so_far;
- char_u *wildcards;
- int level;
- long *countptr;
- {
- char_u *file_name;
- int len;
- char_u *rest_of_wildcards;
- int nFiles = 0;
- char_u **ppFiles;
- int i;
- char_u *c;
- ui_breakcheck();
- if (level > 100 || got_int)
- return NULL;
- if ((file_name = alloc((int)MAXPATHL)) == NULL)
- return NULL;
- STRCPY(file_name, path_so_far);
- len = STRLEN(file_name);
- if (!vim_ispathsep(file_name[len-1]))
- {
- file_name[len++] = PATHSEP;
- file_name[len] = ' ';
- }
- rest_of_wildcards = wildcards;
- if (rest_of_wildcards)
- {
- if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
- rest_of_wildcards++;
- while (*rest_of_wildcards && !vim_ispathsep(*rest_of_wildcards))
- file_name[len++] = *rest_of_wildcards++;
- /* file_name[len++] = *rest_of_wildcards++; */
- rest_of_wildcards++;
- file_name[len] = ' ';
- }
- ++expand_interactively;
- expand_wildcards(1, &file_name, &nFiles, &ppFiles, EW_FILE|EW_DIR);
- --expand_interactively;
- if (!*rest_of_wildcards)
- {
- for (i = 0; i < nFiles; ++i)
- {
- if (!mch_isdir(ppFiles[i]))
- continue; /* not a directory */
- STRCPY(file_name, ppFiles[i]);
- if (!vim_ispathsep(file_name[STRLEN(file_name)-1]))
- STRCAT(file_name, PATHSEPSTR);
- STRCAT(file_name, NameBuff);
- if (mch_getperm(file_name) >= 0 && --*countptr == 0)
- {
- FreeWild(nFiles, ppFiles);
- return file_name;
- }
- }
- }
- else
- {
- for (i = 0; i < nFiles; ++i)
- {
- if (!mch_isdir(ppFiles[i]))
- continue; /* not a directory */
- c = find_file_in_wildcard_path(ppFiles[i],
- rest_of_wildcards, level+1, countptr);
- if (c)
- {
- FreeWild(nFiles, ppFiles);
- vim_free(file_name);
- return c;
- }
- }
- }
- if (STRNCMP(wildcards, "**", 2) == 0)
- {
- for (i = 0; i < nFiles; ++i)
- {
- if (!mch_isdir(ppFiles[i]))
- continue; /* not a directory */
- c = find_file_in_wildcard_path(ppFiles[i],
- wildcards, level+1, countptr);
- if (c)
- {
- FreeWild(nFiles, ppFiles);
- vim_free(file_name);
- return c;
- }
- }
- }
- FreeWild(nFiles, ppFiles);
- vim_free(file_name);
- return NULL;
- }
- /*
- * Check if the "://" of a URL is at the pointer, return URL_SLASH.
- * Also check for ":\", which MS Internet Explorer accepts, return
- * URL_BACKSLASH.
- */
- static int
- path_is_url(p)
- char_u *p;
- {
- if (STRNCMP(p, "://", (size_t)3) == 0)
- return URL_SLASH;
- else if (STRNCMP(p, ":\\", (size_t)3) == 0)
- return URL_BACKSLASH;
- return 0;
- }
- #endif /* FILE_IN_PATH */
- /*
- * Return the minimal number of rows that is needed on the screen to display
- * the current number of windows.
- */
- int
- min_rows()
- {
- WIN *wp;
- int total;
- if (firstwin == NULL) /* not initialized yet */
- return MIN_LINES;
- total = p_ch; /* count the room for the status line */
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- total += p_wmh + wp->w_status_height;
- if (p_wmh == 0)
- total += 1; /* at least one window should have a line! */
- return total;
- }
- /*
- * Return TRUE if there is only one window, not counting a help window, unless
- * it is the current window.
- */
- int
- only_one_window()
- {
- int count = 0;
- WIN *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if (!wp->w_buffer->b_help || wp == curwin)
- ++count;
- return (count <= 1);
- }
- /*
- * Correct the cursor line number in other windows. Used after changing the
- * current buffer, and before applying autocommands.
- * When "do_curwin" is TRUE, also check current window.
- */
- void
- check_lnums(do_curwin)
- int do_curwin;
- {
- WIN *wp;
- for (wp = firstwin; wp != NULL; wp = wp->w_next)
- if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf)
- {
- if (wp->w_cursor.lnum > curbuf->b_ml.ml_line_count)
- wp->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- if (wp->w_topline > curbuf->b_ml.ml_line_count)
- wp->w_topline = curbuf->b_ml.ml_line_count;
- }
- }