9417 lines · 227.2 KB · C
RawDownload
/* 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. * See README.txt for an overview of the Vim source code. */ /* * screen.c: code for displaying on the screen * * Output to the screen (console, terminal emulator or GUI window) is minimized * by remembering what is already on the screen, and only updating the parts * that changed. * * ScreenLines[off]  Contains a copy of the whole screen, as it is currently *		     displayed (excluding text written by external commands). * ScreenAttrs[off]  Contains the associated attributes. * LineOffset[row]   Contains the offset into ScreenLines*[] and ScreenAttrs[] *		     for each line. * LineWraps[row]    Flag for each line whether it wraps to the next line. * * For double-byte characters, two consecutive bytes in ScreenLines[] can form * one character which occupies two display cells. * For UTF-8 a multi-byte character is converted to Unicode and stored in * ScreenLinesUC[].  ScreenLines[] contains the first byte only.  For an ASCII * character without composing chars ScreenLinesUC[] will be 0.  When the * character occupies two display cells the next byte in ScreenLines[] is 0. * ScreenLinesC[][] contain up to 'maxcombine' composing characters * (drawn on top of the first character).  They are 0 when not used. * ScreenLines2[] is only used for euc-jp to store the second byte if the * first byte is 0x8e (single-width character). * * The screen_*() functions write to the screen and handle updating * ScreenLines[]. * * update_screen() is the function that updates all windows and status lines. * It is called form the main loop when must_redraw is non-zero.  It may be * called from other places when an immediate screen update is needed. * * The part of the buffer that is displayed in a window is set with: * - w_topline (first buffer line in window) * - w_topfill (filler line above the first line) * - w_leftcol (leftmost window cell in window), * - w_skipcol (skipped window cells of first line) * * Commands that only move the cursor around in a window, do not need to take * action to update the display.  The main loop will check if w_topline is * valid and update it (scroll the window) when needed. * * Commands that scroll a window change w_topline and must call * check_cursor() to move the cursor into the visible part of the window, and * call redraw_later(VALID) to have the window displayed by update_screen() * later. * * Commands that change text in the buffer must call changed_bytes() or * changed_lines() to mark the area that changed and will require updating * later.  The main loop will call update_screen(), which will update each * window that shows the changed buffer.  This assumes text above the change * can remain displayed as it is.  Text after the change may need updating for * scrolling, folding and syntax highlighting. * * Commands that change how a window is displayed (e.g., setting 'list') or * invalidate the contents of a window in another way (e.g., change fold * settings), must call redraw_later(NOT_VALID) to have the whole window * redisplayed by update_screen() later. * * Commands that change how a buffer is displayed (e.g., setting 'tabstop') * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the * buffer redisplayed by update_screen() later. * * Commands that change highlighting and possibly cause a scroll too must call * redraw_later(SOME_VALID) to update the whole window but still use scrolling * to avoid redrawing everything.  But the length of displayed lines must not * change, use NOT_VALID then. * * Commands that move the window position must call redraw_later(NOT_VALID). * TODO: should minimize redrawing by scrolling when possible. * * Commands that change everything (e.g., resizing the screen) must call * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). * * Things that are handled indirectly: * - When messages scroll the screen up, msg_scrolled will be set and *   update_screen() called to redraw. */ #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 FEAT_SEARCH_EXTRA/* * Struct used for highlighting 'hlsearch' matches for the last use search * pattern or a ":match" item. * For 'hlsearch' there is one pattern for all windows.  For ":match" there is * a different pattern for each window. */typedef struct{    regmmatch_T	rm;	/* points to the regexp program; contains last found			   match (may continue in next line) */    buf_T	*buf;	/* the buffer to search for a match */    linenr_T	lnum;	/* the line to search for a match */    int		attr;	/* attributes to be used for a match */    int		attr_cur; /* attributes currently active in win_line() */    linenr_T	first_lnum;	/* first lnum to search for multi-line pat */    colnr_T	startcol; /* in win_line() points to char where HL starts */    colnr_T	endcol;	 /* in win_line() points to char where HL ends */} match_T; static match_T search_hl;	/* used for 'hlsearch' highlight matching */static match_T match_hl[3];	/* used for ":match" highlight matching */#endif #ifdef FEAT_FOLDINGstatic foldinfo_T win_foldinfo;	/* info for 'foldcolumn' */#endif /* * Buffer for one screen line (characters and attributes). */static schar_T	*current_ScreenLine; static void win_update __ARGS((win_T *wp));static void win_draw_end __ARGS((win_T *wp, int c1, int c2, int row, int endrow, hlf_T hl));#ifdef FEAT_FOLDINGstatic void fold_line __ARGS((win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T lnum, int row));static void fill_foldcolumn __ARGS((char_u *p, win_T *wp, int closed, linenr_T lnum));static void copy_text_attr __ARGS((int off, char_u *buf, int len, int attr));#endifstatic int win_line __ARGS((win_T *, linenr_T, int, int, int nochange));static int char_needs_redraw __ARGS((int off_from, int off_to, int cols));#ifdef FEAT_RIGHTLEFTstatic void screen_line __ARGS((int row, int coloff, int endcol, int clear_width, int rlflag));# define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c), (rl))#elsestatic void screen_line __ARGS((int row, int coloff, int endcol, int clear_width));# define SCREEN_LINE(r, o, e, c, rl)    screen_line((r), (o), (e), (c))#endif#ifdef FEAT_VERTSPLITstatic void draw_vsep_win __ARGS((win_T *wp, int row));#endif#ifdef FEAT_STL_OPTstatic void redraw_custum_statusline __ARGS((win_T *wp));#endif#ifdef FEAT_SEARCH_EXTRAstatic void start_search_hl __ARGS((void));static void end_search_hl __ARGS((void));static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum));static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol));#endifstatic void screen_start_highlight __ARGS((int attr));static void screen_char __ARGS((unsigned off, int row, int col));#ifdef FEAT_MBYTEstatic void screen_char_2 __ARGS((unsigned off, int row, int col));#endifstatic void screenclear2 __ARGS((void));static void lineclear __ARGS((unsigned off, int width));static void lineinvalid __ARGS((unsigned off, int width));#ifdef FEAT_VERTSPLITstatic void linecopy __ARGS((int to, int from, win_T *wp));static void redraw_block __ARGS((int row, int end, win_T *wp));#endifstatic int win_do_lines __ARGS((win_T *wp, int row, int line_count, int mayclear, int del));static void win_rest_invalid __ARGS((win_T *wp));static void msg_pos_mode __ARGS((void));#if defined(FEAT_WINDOWS)static void draw_tabline __ARGS((void));#endif#if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT)static int fillchar_status __ARGS((int *attr, int is_curwin));#endif#ifdef FEAT_VERTSPLITstatic int fillchar_vsep __ARGS((int *attr));#endif#ifdef FEAT_STL_OPTstatic void win_redr_custom __ARGS((win_T *wp, int draw_ruler));#endif#ifdef FEAT_CMDL_INFOstatic void win_redr_ruler __ARGS((win_T *wp, int always));#endif #if defined(FEAT_CLIPBOARD) || defined(FEAT_VERTSPLIT)/* Ugly global: overrule attribute used by screen_char() */static int screen_char_attr = 0;#endif /* * Redraw the current window later, with update_screen(type). * Set must_redraw only if not already set to a higher value. * e.g. if must_redraw is CLEAR, type NOT_VALID will do nothing. */    voidredraw_later(type)    int		type;{    redraw_win_later(curwin, type);}     voidredraw_win_later(wp, type)    win_T	*wp;    int		type;{    if (wp->w_redr_type < type)    {	wp->w_redr_type = type;	if (type >= NOT_VALID)	    wp->w_lines_valid = 0;	if (must_redraw < type)	/* must_redraw is the maximum of all windows */	    must_redraw = type;    }} /* * Force a complete redraw later.  Also resets the highlighting.  To be used * after executing a shell command that messes up the screen. */    voidredraw_later_clear(){    redraw_all_later(CLEAR);#ifdef FEAT_GUI    if (gui.in_use)	/* Use a code that will reset gui.highlight_mask in	 * gui_stop_highlight(). */	screen_attr = HL_ALL + 1;    else#endif	/* Use attributes that is very unlikely to appear in text. */	screen_attr = HL_BOLD | HL_UNDERLINE | HL_INVERSE;} /* * Mark all windows to be redrawn later. */    voidredraw_all_later(type)    int		type;{    win_T	*wp;     FOR_ALL_WINDOWS(wp)    {	redraw_win_later(wp, type);    }} /* * Mark all windows that are editing the current buffer to be updated later. */    voidredraw_curbuf_later(type)    int		type;{    redraw_buf_later(curbuf, type);}     voidredraw_buf_later(buf, type)    buf_T	*buf;    int		type;{    win_T	*wp;     FOR_ALL_WINDOWS(wp)    {	if (wp->w_buffer == buf)	    redraw_win_later(wp, type);    }} /* * Changed something in the current window, at buffer line "lnum", that * requires that line and possibly other lines to be redrawn. * Used when entering/leaving Insert mode with the cursor on a folded line. * Used to remove the "$" from a change command. * Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot * may become invalid and the whole window will have to be redrawn. *//*ARGSUSED*/    voidredrawWinline(lnum, invalid)    linenr_T	lnum;    int		invalid;	/* window line height is invalid now */{#ifdef FEAT_FOLDING    int		i;#endif     if (curwin->w_redraw_top == 0 || curwin->w_redraw_top > lnum)	curwin->w_redraw_top = lnum;    if (curwin->w_redraw_bot == 0 || curwin->w_redraw_bot < lnum)	curwin->w_redraw_bot = lnum;    redraw_later(VALID); #ifdef FEAT_FOLDING    if (invalid)    {	/* A w_lines[] entry for this lnum has become invalid. */	i = find_wl_entry(curwin, lnum);	if (i >= 0)	    curwin->w_lines[i].wl_valid = FALSE;    }#endif} /* * update all windows that are editing the current buffer */    voidupdate_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 ScreenLines[], and update curwin->w_botline. */    voidupdate_screen(type)    int		type;{    win_T	*wp;    static int	did_intro = FALSE;#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)    int		did_one;#endif     if (!screen_valid(TRUE))	return;     if (must_redraw)    {	if (type < must_redraw)	    /* use maximal type */	    type = must_redraw;	must_redraw = 0;    }     /* Need to update w_lines[]. */    if (curwin->w_lines_valid == 0 && type < NOT_VALID)	type = NOT_VALID;     if (!redrawing())    {	redraw_later(type);		/* remember type for next time */	must_redraw = type;	if (type > INVERTED_ALL)	    curwin->w_lines_valid = 0;	/* don't use w_lines[].wl_size now */	return;    }     updating_screen = TRUE;#ifdef FEAT_SYN_HL    ++display_tick;	    /* let syntax code know we're in a next round of			     * display updating */#endif     /*     * 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, NULL) == FAIL)		type = CLEAR;	    FOR_ALL_WINDOWS(wp)	    {		if (W_WINROW(wp) < msg_scrolled)		{		    if (W_WINROW(wp) + wp->w_height > msg_scrolled			    && wp->w_redr_type < REDRAW_TOP			    && wp->w_lines_valid > 0			    && wp->w_topline == wp->w_lines[0].wl_lnum)		    {			wp->w_upd_rows = msg_scrolled - W_WINROW(wp);			wp->w_redr_type = REDRAW_TOP;		    }		    else		    {			wp->w_redr_type = NOT_VALID;#ifdef FEAT_WINDOWS			if (W_WINROW(wp) + wp->w_height + W_STATUS_HEIGHT(wp)				<= msg_scrolled)			    wp->w_redr_status = TRUE;#endif		    }		}	    }	    redraw_cmdline = TRUE;#ifdef FEAT_WINDOWS	    redraw_tabline = TRUE;#endif	}	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)		/* going to clear cmdline (done below) */	check_for_delay(FALSE); #ifdef FEAT_LINEBREAK    /* Force redraw when width of 'number' column changes. */    if (curwin->w_redr_type < NOT_VALID	   && curwin->w_nrwidth != (curwin->w_p_nu ? number_width(curwin) : 0))	curwin->w_redr_type = NOT_VALID;#endif     /*     * Only start redrawing if there is really something to do.     */    if (type == INVERTED)	update_curswant();    if (curwin->w_redr_type < type	    && !((type == VALID		    && curwin->w_lines[0].wl_valid#ifdef FEAT_DIFF		    && curwin->w_topfill == curwin->w_old_topfill		    && curwin->w_botfill == curwin->w_old_botfill#endif		    && curwin->w_topline == curwin->w_lines[0].wl_lnum)#ifdef FEAT_VISUAL		|| (type == INVERTED		    && VIsual_active		    && curwin->w_old_cursor_lnum == curwin->w_cursor.lnum		    && curwin->w_old_visual_mode == VIsual_mode		    && (curwin->w_valid & VALID_VIRTCOL)		    && curwin->w_old_curswant == curwin->w_curswant)#endif		))	curwin->w_redr_type = type; #ifdef FEAT_WINDOWS    /* Redraw the tab pages line if needed. */    if (redraw_tabline || type >= NOT_VALID)	draw_tabline();#endif #ifdef FEAT_SYN_HL    /*     * Correct stored syntax highlighting info for changes in each displayed     * buffer.  Each buffer must only be done once.     */    FOR_ALL_WINDOWS(wp)    {	if (wp->w_buffer->b_mod_set)	{# ifdef FEAT_WINDOWS	    win_T	*wwp; 	    /* Check if we already did this buffer. */	    for (wwp = firstwin; wwp != wp; wwp = wwp->w_next)		if (wwp->w_buffer == wp->w_buffer)		    break;# endif	    if (# ifdef FEAT_WINDOWS		    wwp == wp &&# endif		    syntax_present(wp->w_buffer))		syn_stack_apply_changes(wp->w_buffer);	}    }#endif     /*

Lines 1–500 of 9417.