📄 screen.c
字号:
/* vi:set ts=8 sts=4 sw=4:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* screen.c: code for displaying on the screen
*/
#include "vim.h"
/*
* The attributes that are actually active for writing to the screen.
*/
static int screen_attr = 0;
/*
* Positioning the cursor is reduced by remembering the last position.
* Mostly used by windgoto() and screen_char().
*/
static int screen_cur_row, screen_cur_col; /* last known cursor position */
#ifdef EXTRA_SEARCH
/*
* When highlighting matches for the last use search pattern:
* - search_hl_prog points to the regexp program for it
* - search_hl_attr contains the attributes to be used
* - search_hl_ic is the value for "reg_ic" for this search
*/
vim_regexp *search_hl_prog = NULL;
int search_hl_attr;
int search_hl_ic;
#endif
/*
* Flags for w_valid.
* These are suppose to be used only in screen.c. From other files, use the
* functions that set or reset them.
*
* VALID_BOTLINE VALID_BOTLINE_AP
* on on w_botline valid
* off on w_botline approximated
* off off w_botline not valid
* on off not possible
*/
#define VALID_WROW 0x01 /* w_wrow (window row) is valid */
#define VALID_WCOL 0x02 /* w_wcol (window col) is valid */
#define VALID_VIRTCOL 0x04 /* w_virtcol (file col) is valid */
#define VALID_CHEIGHT 0x08 /* w_cline_height is valid */
#define VALID_CROW 0x10 /* w_cline_row is valid */
#define VALID_BOTLINE 0x20 /* w_botine and w_empty_rows are valid */
#define VALID_BOTLINE_AP 0x40 /* w_botine is approximated */
/*
* Buffer for one screen line.
*/
static char_u *current_LinePointer;
static void win_update __ARGS((WIN *wp));
static int win_line __ARGS((WIN *, linenr_t, int, int));
#ifdef RIGHTLEFT
static void screen_line __ARGS((int row, int endcol, int clear_rest, int rlflag));
#define SCREEN_LINE(r, e, c, rl) screen_line((r), (e), (c), (rl))
#else
static void screen_line __ARGS((int row, int endcol, int clear_rest));
#define SCREEN_LINE(r, e, c, rl) screen_line((r), (e), (c))
#endif
#ifdef EXTRA_SEARCH
static void start_search_hl __ARGS((void));
static void end_search_hl __ARGS((void));
#endif
static void screen_start_highlight __ARGS((int attr));
static void comp_botline __ARGS((void));
static void screen_char __ARGS((char_u *, int, int));
static void screenclear2 __ARGS((void));
static void lineclear __ARGS((char_u *p));
static void check_cursor_moved __ARGS((WIN *wp));
static void curs_rows __ARGS((int do_botline));
static void validate_virtcol_win __ARGS((WIN *wp));
static int screen_ins_lines __ARGS((int, int, int, int));
static int highlight_status __ARGS((int *attr, int is_curwin));
static void win_redr_ruler __ARGS((WIN *wp, int always));
static void intro_message __ARGS((void));
/*
* update_screenline() - like update_screen() but only for cursor line
*
* Must only be called when something in the cursor line has changed (e.g.
* character inserted or deleted).
*
* Check if the size of the cursor line has changed since the last screen
* update. If it did change, lines below the cursor will move up or down and
* we need to call the routine update_screen() to examine the entire screen.
*/
void
update_screenline()
{
int row;
int old_cline_height;
if (!screen_valid(TRUE))
return;
if (must_redraw) /* must redraw whole screen */
{
update_screen(must_redraw);
return;
}
if (!redrawing())
{
redraw_later(NOT_VALID); /* remember to update later */
return;
}
/*
* If the screen has scrolled, or some lines after the cursor line have
* been invalidated, call update_screen().
*/
if (curwin->w_lsize_valid <= curwin->w_cursor.lnum - curwin->w_topline ||
curwin->w_lsize_lnum[0] != curwin->w_topline)
{
update_screen(VALID_TO_CURSCHAR);
return;
}
/*
* Get the current height of the cursor line, as it is on the screen.
* w_lsize[] must be used here, since w_cline_height might already have
* been updated to the new height of the line in the buffer.
*/
old_cline_height = curwin->w_lsize[curwin->w_cursor.lnum
- curwin->w_topline];
/*
* Check if the cursor line is still at the same position. Be aware of
* the cursor having moved around, w_cline_row may be invalid, use the
* values from w_lsize[] by calling curs_rows().
*/
check_cursor_moved(curwin);
if (!(curwin->w_valid & VALID_CROW))
curs_rows(FALSE);
#ifdef EXTRA_SEARCH
start_search_hl();
#endif
/*
* w_virtcol needs to be valid.
*/
validate_virtcol();
cursor_off();
row = win_line(curwin, curwin->w_cursor.lnum,
curwin->w_cline_row, curwin->w_height);
display_hint = HINT_NONE;
#ifdef EXTRA_SEARCH
end_search_hl();
#endif
if (row == curwin->w_height + 1) /* line too long for window */
{
if (curwin->w_topline < curwin->w_cursor.lnum)
{
/*
* Window needs to be scrolled up to show the cursor line.
* We know w_botline was valid before the change, so it should now
* be one less. This removes the need to recompute w_botline in
* update_topline().
*/
--curwin->w_botline;
curwin->w_valid |= VALID_BOTLINE_AP;
}
update_topline();
update_screen(VALID_TO_CURSCHAR);
}
else if (!dollar_vcol)
{
/*
* If the cursor line changed size, delete or insert screen lines and
* redraw the rest of the window.
*/
if (old_cline_height != curwin->w_cline_height)
{
if (curwin->w_cline_height < old_cline_height)
win_del_lines(curwin, row,
old_cline_height - curwin->w_cline_height, FALSE, TRUE);
else
win_ins_lines(curwin,
curwin->w_cline_row + curwin->w_cline_height,
curwin->w_cline_height - old_cline_height, FALSE, TRUE);
update_screen(VALID_TO_CURSCHAR);
}
#ifdef SYNTAX_HL
/*
* If syntax lost its sync, have to redraw the following lines.
*/
else if (syntax_present(curbuf) && row < cmdline_row
&& syntax_check_changed(curwin->w_cursor.lnum + 1))
update_screen(VALID_TO_CURSCHAR);
#endif
else if (clear_cmdline || redraw_cmdline)
showmode(); /* clear cmdline, show mode and ruler */
}
}
/*
* Redraw the current window later, with UpdateScreen(type).
* Set must_redraw only of not already set to a higher value.
* e.g. if must_redraw is CLEAR, type == NOT_VALID will do nothing.
*/
void
redraw_later(type)
int type;
{
if (curwin->w_redr_type < type)
curwin->w_redr_type = type;
if (must_redraw < type) /* must_redraw is the maximum of all windows */
must_redraw = type;
}
/*
* Mark all windows to be redrawn later.
*/
void
redraw_all_later(type)
int type;
{
WIN *wp;
for (wp = firstwin; wp; wp = wp->w_next)
if (wp->w_redr_type < type)
wp->w_redr_type = type;
redraw_later(type);
}
/*
* Mark all windows that are editing the current buffer to be udpated later.
*/
void
redraw_curbuf_later(type)
int type;
{
WIN *wp;
for (wp = firstwin; wp; wp = wp->w_next)
if (wp->w_redr_type < type && wp->w_buffer == curbuf)
wp->w_redr_type = type;
redraw_later(type);
}
/*
* update all windows that are editing the current buffer
*/
void
update_curbuf(type)
int type;
{
redraw_curbuf_later(type);
update_screen(type);
}
/*
* update_screen()
*
* Based on the current value of curwin->w_topline, transfer a screenfull
* of stuff from Filemem to NextScreen, and update curwin->w_botline.
*/
void
update_screen(type)
int type;
{
WIN *wp;
static int did_intro = FALSE;
if (!screen_valid(TRUE))
return;
dollar_vcol = 0;
if (must_redraw)
{
if (type < must_redraw) /* use maximal type */
type = must_redraw;
must_redraw = 0;
}
if (curwin->w_lsize_valid == 0 && type < NOT_VALID)
type = NOT_VALID;
if (!redrawing())
{
redraw_later(type); /* remember type for next time */
curwin->w_redr_type = type;
curwin->w_lsize_valid = 0; /* don't use w_lsize[] now */
return;
}
/*
* if the screen was scrolled up when displaying a message, scroll it down
*/
if (msg_scrolled)
{
clear_cmdline = TRUE;
if (msg_scrolled > Rows - 5) /* clearing is faster */
type = CLEAR;
else if (type != CLEAR)
{
check_for_delay(FALSE);
if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows) == FAIL)
type = CLEAR;
win_rest_invalid(firstwin); /* should do only first/last few */
}
msg_scrolled = 0;
need_wait_return = FALSE;
}
/* reset cmdline_row now (may have been changed temporarily) */
compute_cmdrow();
/* Check for changed highlighting */
if (need_highlight_changed)
highlight_changed();
if (type == CLEAR) /* first clear screen */
{
screenclear(); /* will reset clear_cmdline */
type = NOT_VALID;
}
if (clear_cmdline) /* first clear cmdline */
{
check_for_delay(FALSE);
msg_clr_cmdline(); /* will reset clear_cmdline */
}
/*
* Only start redrawing if there is really something to do.
*/
if (type == INVERTED)
update_curswant();
if (!((type == VALID && curwin->w_topline == curwin->w_lsize_lnum[0])
|| (type == INVERTED
&& curwin->w_old_cursor_lnum == curwin->w_cursor.lnum
&& (curwin->w_valid & VALID_VIRTCOL)
&& curwin->w_old_curswant == curwin->w_curswant)))
{
/*
* go from top to bottom through the windows, redrawing the ones that
* need it
*/
curwin->w_redr_type = type;
cursor_off();
#ifdef EXTRA_SEARCH
start_search_hl();
#endif
for (wp = firstwin; wp; wp = wp->w_next)
{
if (wp->w_redr_type)
win_update(wp);
if (wp->w_redr_status)
win_redr_status(wp);
}
#ifdef EXTRA_SEARCH
end_search_hl();
#endif
}
if (redraw_cmdline)
showmode();
display_hint = HINT_NONE;
/* May put up an introductory message when not editing a file */
if (!did_intro && bufempty()
&& curbuf->b_fname == NULL
&& firstwin->w_next == NULL
&& vim_strchr(p_shm, SHM_INTRO) == NULL)
intro_message();
did_intro = TRUE;
}
#ifdef USE_GUI
/*
* Update a single window, its status line and maybe the command line msg.
* Used for the GUI scrollbar.
*/
void
updateWindow(wp)
WIN *wp;
{
cursor_off();
#ifdef EXTRA_SEARCH
start_search_hl();
#endif
win_update(wp);
if (wp->w_redr_status || p_ru)
win_redr_status(wp);
if (redraw_cmdline)
showmode();
#ifdef EXTRA_SEARCH
end_search_hl();
#endif
}
#endif
/*
* Update all windows for the current buffer, except curwin.
* Used after modifying text, to update the other windows on the same buffer.
*/
void
update_other_win()
{
WIN *wp;
int first = TRUE;
for (wp = firstwin; wp; wp = wp->w_next)
if (wp != curwin && wp->w_buffer == curbuf)
{
if (first)
{
cursor_off();
#ifdef EXTRA_SEARCH
start_search_hl();
#endif
first = FALSE;
}
wp->w_redr_type = NOT_VALID;
/*
* don't do the actual redraw if wait_return() has just been
* called and the user typed a ":"
*/
if (!skip_redraw)
win_update(wp);
}
#ifdef EXTRA_SEARCH
end_search_hl();
#endif
}
/*
* Update a single window.
*
* This may cause the windows below it also to be redrawn.
*/
static void
win_update(wp)
WIN *wp;
{
int type;
int row;
int endrow;
linenr_t lnum;
linenr_t lastline; /* only valid if endrow != Rows -1 */
int done; /* if TRUE, we hit the end of the file */
int didline; /* if TRUE, we finished the last line */
int srow = 0; /* starting row of the current line */
int idx;
int i;
long j;
static int recursive = FALSE; /* being called recursively */
int old_botline = wp->w_botline;
int must_start_top = FALSE; /* update must start at top row */
int must_end_bot = FALSE; /* update must end at bottom row */
type = wp->w_redr_type;
if (type == NOT_VALID)
{
wp->w_redr_status = TRUE;
wp->w_lsize_valid = 0;
}
wp->w_redr_type = 0; /* reset it now, may be set again later */
idx = 0;
row = 0;
lnum = wp->w_topline;
validate_virtcol_win(wp);
/* The number of rows shown is w_height. */
/* The default last row is the status/command line. */
endrow = wp->w_height;
/*
* If there are no changes on the screen, handle two special cases:
* 1: we are off the top of the screen by a few lines: scroll down
* 2: wp->w_topline is below wp->w_lsize_lnum[0]: may scroll up
*/
if (type == VALID || type == VALID_TO_CURSCHAR ||
type == VALID_BEF_CURSCHAR || type == INVERTED)
{
if (wp->w_topline < wp->w_lsize_lnum[0]) /* may scroll down */
{
j = wp->w_lsize_lnum[0] - wp->w_topline;
if (j < wp->w_height - 2 /* not too far off */
&& (type != VALID_TO_CURSCHAR
|| wp->w_lsize_lnum[0] < curwin->w_cursor.lnum)
&& (type != VALID_BEF_CURSCHAR
|| wp->w_lsize_lnum[0] < curwin->w_cursor.lnum - 1))
{
lastline = wp->w_lsize_lnum[0] - 1;
i = plines_m_win(wp, wp->w_topline, lastline);
if (i < wp->w_height - 2) /* less than a screen off */
{
/*
* Try to insert the correct number of lines.
* If not the last window, delete the lines at the bottom.
* win_ins_lines may fail.
*/
if (i > 0)
check_for_delay(FALSE);
if (win_ins_lines(wp, 0, i, FALSE, wp == firstwin) == OK
&& wp->w_lsize_valid)
{
must_start_top = TRUE;
endrow = i;
/* If there are changes, must redraw the rest too */
if (type == VALID_TO_CURSCHAR
|| type == VALID_BEF_CURSCHAR)
wp->w_redr_type = type;
if ((wp->w_lsize_valid += j) > wp->w_height)
wp->w_lsize_valid = wp->w_height;
for (idx = wp->w_lsize_valid; idx - j >= 0; idx--)
{
wp->w_lsize_lnum[idx] = wp->w_lsize_lnum[idx - j];
wp->w_lsize[idx] = wp->w_lsize[idx - j];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -