⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 screen.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -