📄 window.c
字号:
/* 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 *)"new\n"); /* it is ex_docmd.c */
break;
/* quit current window */
case Ctrl('Q'):
case 'q': reset_VIsual(); /* stop Visual mode */
stuffReadbuff((char_u *)":quit\n"); /* it is ex_docmd.c */
break;
/* close current window */
case Ctrl('C'):
case 'c': reset_VIsual(); /* stop Visual mode */
stuffReadbuff((char_u *)":close\n"); /* it is ex_docmd.c */
break;
/* close all but current window */
case Ctrl('O'):
case 'o': reset_VIsual(); /* stop Visual mode */
stuffReadbuff((char_u *)":only\n"); /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -