📄 window.c
字号:
}
#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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -