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

📄 syntax.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
    }

    /*
     * Remove items from b_syn_states[] that have changes in or before them.
     */
    if (syn_buf->b_syn_change_lnum != MAXLNUM)
    {
	/* if change is before the end of the array, something to clear */
	if (syn_buf->b_syn_change_lnum <
		   syn_buf->b_syn_states_lnum + syn_buf->b_syn_states_len - 1)
	{
	    /* line before the start changed: clear all entries */
	    if (syn_buf->b_syn_change_lnum < syn_buf->b_syn_states_lnum)
		idx = 0;
	    else
		idx = syn_buf->b_syn_change_lnum -
					       syn_buf->b_syn_states_lnum + 1;
	    syn_clear_states(idx, syn_buf->b_syn_states_len);
	}
	if (syn_buf->b_syn_change_lnum <= current_lnum)
	    invalidate_current_state();
	syn_buf->b_syn_change_lnum = MAXLNUM;
    }

    /*
     * If the topline has changed out of range of b_syn_states[], move the
     * items in the array.
     */
    if (wp->w_topline < syn_buf->b_syn_states_lnum)
    {
	/*
	 * Topline is above the array: Move entries down.
	 * (w_topline - SYNC_LINES) is the new first line in * b_syn_states[].
	 */
	to = syn_buf->b_syn_states_len - 1;
	if (wp->w_topline > SYNC_LINES)
	    first = wp->w_topline - SYNC_LINES;
	else
	    first = 0;
	from = to - (syn_buf->b_syn_states_lnum - first);
	while (from >= 0)
	{
	    move_state((int)from, (int)to);
	    --from;
	    --to;
	}
	syn_clear_states(0, (int)(to + 1));
	syn_buf->b_syn_states_lnum = first;
    }
    else if ((diff = (wp->w_topline + wp->w_height) -
		 (syn_buf->b_syn_states_lnum + syn_buf->b_syn_states_len)) > 0)
    {
	/*
	 * The last line in the window is below the array: Move entries up
	 * "diff" positions.
	 */
	to = 0;
	from = to + diff;
	while (from < syn_buf->b_syn_states_len)
	{
	    move_state((int)from, (int)to);
	    ++from;
	    ++to;
	}
	syn_clear_states((int)to, syn_buf->b_syn_states_len);
	syn_buf->b_syn_states_lnum += diff;
    }

    /*
     * If the state of the end of the previous line is useful, store it.
     */
    if (VALID_STATE(&current_state)
	    && current_lnum < lnum
	    && current_lnum >= syn_buf->b_syn_states_lnum
	    && current_lnum <
			syn_buf->b_syn_states_lnum + syn_buf->b_syn_states_len
	    && current_lnum < syn_buf->b_ml.ml_line_count)
    {
	(void)syn_finish_line(FALSE);
	if (!current_state_stored)
	{
	    ++current_lnum;
	    store_current_state();
	}

	/*
	 * If the current_lnum is now the same as "lnum", keep the current
	 * state (this happens very often!).  Otherwise invalidate
	 * current_state and figure it out below.
	 */
	if (current_lnum != lnum)
	    invalidate_current_state();
    }
    else
	invalidate_current_state();


    /*
     * Try to synchronize from a saved state in b_syn_states[].
     * Only do this if lnum is not before and not to far beyond a saved state.
     */
    if (INVALID_STATE(&current_state))
    {
	diff = syn_buf->b_syn_sync_minlines;
	if (diff < Rows * 2)
	    diff = Rows * 2;	    /* parse less then two screenfulls extra */
	if (lnum >= syn_buf->b_syn_states_lnum &&
		lnum <= syn_buf->b_syn_states_lnum +
					     syn_buf->b_syn_states_len + diff)
	{
	    idx = lnum - syn_buf->b_syn_states_lnum;
	    if (idx >= syn_buf->b_syn_states_len)
		idx = syn_buf->b_syn_states_len - 1;
	    for ( ; idx >= 0; --idx)
	    {
		if (VALID_STATE(&syn_buf->b_syn_states[idx].sst_ga))
		{
		    current_lnum = syn_buf->b_syn_states_lnum + idx;
		    copy_state_to_current(&(syn_buf->b_syn_states[idx]));
		    break;
		}
	    }
	}
    }

    /*
     * If "lnum" is before or far beyond a line with a saved state, need to
     * re-synchronize.
     */
    if (INVALID_STATE(&current_state))
	syn_sync(wp, lnum);

    /*
     * Advance from the sync point or saved state until the current line.
     */
    while (current_lnum < lnum)
    {
	syn_start_line();
	(void)syn_finish_line(FALSE);
	++current_lnum;
	store_current_state();

	/* This can take a long time: break when CTRL-C pressed. */
	line_breakcheck();
	if (got_int)
	{
	    current_lnum = lnum;
	    break;
	}
    }

    syn_start_line();

theend:
    reg_syn = FALSE;
}

/*
 * Try to find a synchronisation point for line "lnum".
 *
 * This sets current_lnum and the current state.  One of three methods is
 * used:
 * 1. Search backwards for the end of a C-comment.
 * 2. Search backwards for given sync patterns.
 * 3. Simply start on a given number of lines above "lnum".
 */
    static void
syn_sync(wp, start_lnum)
    WIN		*wp;
    linenr_t	start_lnum;
{
    BUF			*curbuf_save;
    WIN			*curwin_save;
    FPOS		cursor_save;
    int			idx;
    linenr_t		lnum;
    linenr_t		end_lnum;
    linenr_t		break_lnum;
    int			had_sync_point;
    struct state_item	*cur_si;
    struct syn_pattern	*spp;
    char_u		*line;
    int			found_flags = 0;
    int			found_match_idx = 0;
    linenr_t		found_current_lnum = 0;
    int			found_current_col= 0;
    colnr_t		found_m_endcol = 0;

    /*
     * Clear any current state that might be hanging around.
     */
    invalidate_current_state();

    /*
     * Start at least "minlines" back.
     * Also subtract SYNC_LINES, so that b_syn_states[] is filled with valid
     * states.
     * Default starting point for parsing is there.
     */
    start_lnum -= syn_buf->b_syn_sync_minlines + SYNC_LINES;
    if (start_lnum < 1)
	start_lnum = 1;
    current_lnum = start_lnum;

    /*
     * 1. Search backwards for the end of a C-style comment.
     */
    if (syn_buf->b_syn_sync_flags & SF_CCOMMENT)
    {
	/* need to make syn_buf the current buffer for a moment */
	curwin_save = curwin;
	curwin = wp;
	curbuf_save = curbuf;
	curbuf = syn_buf;

	/*
	 * Skip lines that end in a backslash.
	 */
	for ( ; start_lnum > 1; --start_lnum)
	{
	    line = ml_get(start_lnum - 1);
	    if (*line == NUL || *(line + STRLEN(line) - 1) != '\\')
		break;
	}
	current_lnum = start_lnum;

	/* set cursor to start of search */
	cursor_save = wp->w_cursor;
	wp->w_cursor.lnum = start_lnum;
	wp->w_cursor.col = 0;

	/*
	 * If the line is inside a comment, need to find the syntax item that
	 * defines the comment.
	 * Restrict the search for the end of a comment to b_syn_sync_maxlines.
	 */
	if (find_start_comment((int)syn_buf->b_syn_sync_maxlines) != NULL)
	{
	    for (idx = syn_buf->b_syn_patterns.ga_len; --idx >= 0; )
		if (SYN_ITEMS(syn_buf)[idx].sp_syn_id == syn_buf->b_syn_sync_id
			&& SYN_ITEMS(syn_buf)[idx].sp_type == SPTYPE_START)
		{
		    validate_current_state();
		    if (push_current(idx) == OK)
			update_si_attr(current_state.ga_len - 1);
		    break;
		}
	}

	/* restore cursor and buffer */
	wp->w_cursor = cursor_save;
	curwin = curwin_save;
	curbuf = curbuf_save;
    }

    /*
     * 2. Search backwards for given sync patterns.
     */
    else if (syn_buf->b_syn_sync_flags & SF_MATCH)
    {
	if (syn_buf->b_syn_sync_maxlines
				 && start_lnum > syn_buf->b_syn_sync_maxlines)
	    break_lnum = start_lnum - syn_buf->b_syn_sync_maxlines;
	else
	    break_lnum = 0;

	end_lnum = start_lnum;
	lnum = start_lnum;
	while (--lnum > break_lnum)
	{
	    /* This can take a long time: break when CTRL-C pressed. */
	    line_breakcheck();
	    if (got_int)
	    {
		invalidate_current_state();
		current_lnum = start_lnum;
		break;
	    }

	    /*
	     * Check if the previous line has the line-continuation pattern.
	     */
	    if (lnum > 1 && syn_match_linecont(lnum - 1))
		continue;

	    /*
	     * Start with nothing on the state stack
	     */
	    validate_current_state();

	    for (current_lnum = lnum; current_lnum < end_lnum; ++current_lnum)
	    {
		syn_start_line();
		for (;;)
		{
		    had_sync_point = syn_finish_line(TRUE);
		    /*
		     * When a sync point has been found, remember where, and
		     * continue to look for another one, further on in the line.
		     */
		    if (had_sync_point && current_state.ga_len)
		    {
			cur_si = &CUR_STATE(current_state.ga_len - 1);
			spp = &(SYN_ITEMS(syn_buf)[cur_si->si_idx]);
			found_flags = spp->sp_flags;
			found_match_idx = spp->sp_sync_idx;
			found_current_lnum = current_lnum;
			found_current_col = current_col;
			found_m_endcol = cur_si->si_m_endcol;
			/*
			 * Continue after the match (be aware of a zero-length
			 * match).
			 */
			if (found_m_endcol > current_col)
			    current_col = found_m_endcol;
			else
			    ++current_col;

			/* syn_current_attr() will have skipped the check for
			 * an item that ends here, need to do that now. */
			++current_col;
			check_state_ends(
				    ml_get_buf(syn_buf, current_lnum, FALSE));
			--current_col;
		    }
		    else
			break;
		}
	    }

	    /*
	     * If a sync point was encountered, break here.
	     */
	    if (found_flags)
	    {
		/*
		 * Put the item that was specified by the sync point on the
		 * state stack.  If there was no item specified, make the
		 * state stack empty.
		 */
		ga_clear(&current_state);
		if (found_match_idx >= 0 &&
			push_current(found_match_idx) == OK)
		    update_si_attr(current_state.ga_len - 1);

		/*
		 * When using "grouphere", continue from the sync point
		 * match, until the end of the line.  Parsing starts at
		 * the next line.
		 * For "groupthere" the parsing starts at start_lnum.
		 */
		if (found_flags & HL_SYNC_HERE)
		{
		    if (current_state.ga_len)
		    {
			cur_si = &CUR_STATE(current_state.ga_len - 1);
			cur_si->si_h_startcol = found_current_col;
			line = ml_get_buf(syn_buf, current_lnum, FALSE);
			update_si_end(cur_si, line, current_col);
		    }
		    current_col = found_m_endcol;
		    current_lnum = found_current_lnum;
		    (void)syn_finish_line(FALSE);
		    ++current_lnum;
		}
		else
		    current_lnum = start_lnum;

		break;
	    }

	    end_lnum = lnum;
	    invalidate_current_state();
	}

	/* Ran into start of the file or exceeded maximum number of lines */
	if (lnum <= break_lnum)
	{
	    invalidate_current_state();
	    current_lnum = break_lnum + 1;
	}
    }

    validate_current_state();
}

/*
 * Return TRUE if the line-continuation pattern matches in line "lnum".
 */
    static int
syn_match_linecont(lnum)
    linenr_t	    lnum;
{
    if (syn_buf->b_syn_linecont_prog != NULL)
    {
	reg_ic = syn_buf->b_syn_linecont_ic;
	return syn_regexec(syn_buf->b_syn_linecont_prog,
				      ml_get_buf(syn_buf, lnum, FALSE), TRUE);
    }
    return FALSE;
}

/*
 * Set the state for the start of a line.
 */
    static void
syn_start_line()
{
    char_u		*line;
    struct state_item	*cur_si;
    int			i;

    current_finished = FALSE;
    current_col = 0;

    /*
     * Need to update the end of a start/skip/end that continues from the
     * previous line.  And regions that have "keepend", because they may
     * influence contained items.
     * Then check for items ending in column 0.
     */
    if (current_state.ga_len)
    {
	line = ml_get_buf(syn_buf, current_lnum, FALSE);
	for (i = 0; i < current_state.ga_len; ++i)
	{
	    cur_si = &CUR_STATE(i);
	    if ((cur_si->si_flags & HL_KEEPEND)
					     || i == current_state.ga_len - 1)
	    {
		cur_si->si_h_startcol = 0;	/* start highl. in col 0 */
		update_si_end(cur_si, line, 0);
	    }
	}
	check_state_ends(line);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -