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

📄 syntax.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
    }
    next_match_idx = -1;
    ++current_line_id;
}

/*
 * Free b_syn_states[] for buffer "buf".
 */
    static void
syn_free_all_states(buf)
    BUF	    *buf;
{
    int	    idx;

    if (buf->b_syn_states != NULL)
    {
	for (idx = 0; idx < buf->b_syn_states_len; ++idx)
	    ga_clear(&(buf->b_syn_states[idx].sst_ga));
	vim_free(buf->b_syn_states);
	buf->b_syn_states = NULL;
	buf->b_syn_states_len = 0;
    }
}

/*
 * clear the entries in b_syn_states[] from "start" to (not including) "end"
 */
    static void
syn_clear_states(start, end)
    int		start, end;
{
    int		idx;
    struct	growarray *sp;

    for (idx = start; idx < end; ++idx)
    {
	sp = &(syn_buf->b_syn_states[idx].sst_ga);
	ga_clear(sp);
	sp->ga_itemsize = 0;
    }
}

/*
 * Try saving the current state in b_syn_states[].
 * The current state must be at the start of the current_lnum line!
 */
    static void
store_current_state()
{
    long		idx;
    int			i;
    struct growarray	*to;

    idx = current_lnum - syn_buf->b_syn_states_lnum;
    if (idx >= 0 && idx < syn_buf->b_syn_states_len)
    {
	to = &(syn_buf->b_syn_states[idx].sst_ga);
	if (to->ga_data != NULL)
	    ga_clear(to);
	else if (to->ga_itemsize == 0)
	{
	    to->ga_itemsize = sizeof(struct buf_state);
	    to->ga_growsize = 3;
	}
	if (current_state.ga_len && ga_grow(to, current_state.ga_len) != FAIL)
	{
	    for (i = 0; i < current_state.ga_len; ++i)
	    {
		SYN_STATE_P(to)[i].bs_idx = CUR_STATE(i).si_idx;
		SYN_STATE_P(to)[i].bs_flags = CUR_STATE(i).si_flags;
	    }
	    to->ga_len = current_state.ga_len;
	    to->ga_room -= to->ga_len;
	}
	syn_buf->b_syn_states[idx].sst_next_list = current_next_list;
	syn_buf->b_syn_states[idx].sst_next_flags = current_next_flags;
    }
    current_state_stored = TRUE;
}

/*
 * Copy a state stack from "from" in b_syn_states[] to current_state;
 */
    static void
copy_state_to_current(from)
    struct syn_state *from;
{
    int	    i;
    struct growarray	*ga = &(from->sst_ga);

    ga_clear(&current_state);
    validate_current_state();
    keepend_level = -1;
    if (ga->ga_len && ga_grow(&current_state, ga->ga_len) != FAIL)
    {
	for (i = 0; i < ga->ga_len; ++i)
	{
	    CUR_STATE(i).si_idx = SYN_STATE_P(ga)[i].bs_idx;
	    CUR_STATE(i).si_flags = SYN_STATE_P(ga)[i].bs_flags;
	    if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND))
		keepend_level = i;
	    CUR_STATE(i).si_m_endcol = 0;
	    CUR_STATE(i).si_m_startcol = 0;
	    CUR_STATE(i).si_m_lnum = 0;
	    update_si_attr(i);
	}
	current_state.ga_len = ga->ga_len;
	current_state.ga_room -= current_state.ga_len;
    }
    current_next_list = from->sst_next_list;
    current_next_flags = from->sst_next_flags;
}

    static void
invalidate_current_state()
{
    ga_clear(&current_state);
    current_state.ga_itemsize = 0;
    current_next_list = NULL;
    keepend_level = -1;
}

    static void
validate_current_state()
{
    current_state.ga_itemsize = sizeof(struct state_item);
    current_state.ga_growsize = 3;
}

/*
 * Move a state stack from b_syn_states[from] to b_syn_states[to].
 */
    static void
move_state(from, to)
    int	    from, to;
{
    ga_clear(&(syn_buf->b_syn_states[to].sst_ga));
    syn_buf->b_syn_states[to] = syn_buf->b_syn_states[from];
    ga_init(&(syn_buf->b_syn_states[from].sst_ga));
    syn_buf->b_syn_states[from].sst_ga.ga_itemsize = 0;	/* invalid entry */
}

/*
 * Mark like "lnum" and following ones as changed: Need to recompute its
 * highlighting.
 * This must be called whenever something is changed.  ml_delete() and
 * ml_append() take care of this when deleting/appending lines.
 * When changing a single line, and calling update_screenline(), for it, no
 * need to call this (syntax_check_changed() will be used then).
 */
    void
syn_changed(lnum)
    linenr_t	lnum;
{
    if (curbuf->b_syn_change_lnum > lnum)
	curbuf->b_syn_change_lnum = lnum;
}

/*
 * Return TRUE if the syntax at start of lnum changed since last time.
 * This will only be called just after get_syntax_attr for the previous line,
 * to check if the next line needs to be redrawn too.
 */
    int
syntax_check_changed(lnum)
    linenr_t	lnum;
{
    struct growarray	*ssp;
    int			i;
    int			retval = TRUE;
    long		idx;

    reg_syn = TRUE;	/* let vim_regexec() know we're using syntax */

    /*
     * Check the state stack when:
     * - lnum is just below the previously syntaxed line.
     * - lnum is not before the lines with saved states.
     * - lnum is not past the lines with saved states.
     * - lnum is at or before the last changed line.
     */
    idx = lnum - syn_buf->b_syn_states_lnum;
    if (VALID_STATE(&current_state) && lnum == current_lnum + 1 &&
	    idx >= 0 && idx < syn_buf->b_syn_states_len &&
	    lnum < syn_buf->b_syn_change_lnum)
    {
	/*
	 * finish the previous line (needed when not all of the line was drawn)
	 */
	(void)syn_finish_line(FALSE);

	ssp = &(syn_buf->b_syn_states[idx].sst_ga);
	if (VALID_STATE(ssp))	/* entry is valid */
	{
	    /*
	     * Compare the current state with the previously saved state of
	     * the line.
	     */
	    if (ssp->ga_len == current_state.ga_len
		    && syn_buf->b_syn_states[idx].sst_next_list
							 == current_next_list)
	    {
		for (i = current_state.ga_len; --i >= 0; )
		    if (SYN_STATE_P(ssp)[i].bs_idx != CUR_STATE(i).si_idx)
			break;
		/*
		 * If still the same state, return FALSE, syntax didn't change.
		 */
		if (i < 0)
		    retval = FALSE;
	    }
	}

	/*
	 * Store the current state in b_syn_states[] for later use.
	 */
	++current_lnum;
	store_current_state();
    }

    reg_syn = FALSE;

    /* If state has changed, the saved states are invalid now */
    if (retval)
	syn_changed(lnum);

    return retval;
}

/*
 * Finish the current line.
 * This doesn't return any attributes, it only gets the state at the end of
 * the line.  It can start anywhere in the line, as long as the current state
 * is valid.
 */
    static int
syn_finish_line(syncing)
    int	    syncing;		/* called for syncing */
{
    char_u		*line;
    struct state_item	*cur_si;

    if (!current_finished)
    {
	line = ml_get_buf(syn_buf, current_lnum, FALSE);
	while (!current_finished)
	{
	    (void)syn_current_attr(syncing, line);
	    /*
	     * When syncing, and found some item, need to check the item.
	     */
	    if (syncing && current_state.ga_len)
	    {
		/*
		 * Check for match with sync item.
		 */
		cur_si = &CUR_STATE(current_state.ga_len - 1);
		if (SYN_ITEMS(syn_buf)[cur_si->si_idx].sp_flags
					       & (HL_SYNC_HERE|HL_SYNC_THERE))
		    return TRUE;

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

/*
 * Return highlight attributes for next character.
 * This function is alwyas called from the screen updating, for each
 * consecutive character.  And only after syntax_start() has been called for
 * the current line.
 * Note that "col" doesn't start at 0, when win->w_leftcol is non-zero, and
 * doesn't continue until the last col when 'nowrap' is set.
 */
    int
get_syntax_attr(col, line)
    colnr_t	col;
    char_u	*line;
{
    int	    attr = 0;

    reg_syn = TRUE;	/* let vim_regexec() know we're using syntax */

    /* check for out of memory situation */
    if (syn_buf->b_syn_states_len == 0)
	return 0;

    /* Make sure current_state is valid */
    if (INVALID_STATE(&current_state))
	validate_current_state();

    /*
     * Skip from the current column to "col", get the attributes for "col".
     */
    while (current_col <= col)
    {
	attr = syn_current_attr(FALSE, line);
	++current_col;
    }

    reg_syn = FALSE;
    return attr;
}

/*
 * Get syntax attributes for current_lnum, current_col.
 */
    static int
syn_current_attr(syncing, line)
    int		syncing;	    /* When 1: called for syncing */
    char_u	*line;
{
    int			syn_id;
    char_u		*endp;
    char_u		*hl_endp = NULL;
    char_u		*eoep;	    /* end-of-end pattern */
    int			end_idx;    /* group ID for end pattern */
    int			idx;
    struct syn_pattern	*spp;
    struct state_item	*cur_si, *sip;
    int			startcol;
    int			hl_startcol;
    int			eos_col;    /* end-of-start column */
    int			endcol;
    int			flags;
    short		*next_list;
    int			found_match;		    /* found usable match */
    static int		try_next_column = FALSE;    /* must try in next col */

    /*
     * No character, no attributes!  Past end of line?
     * Do try matching with an empty line (could be the start of a region).
     */
    if (*(line + current_col) == NUL && current_col != 0)
    {
	/*
	 * If we found a match after the last column, use it.
	 */
	if (next_match_idx >= 0 && next_match_col >= (int)current_col
						  && next_match_col != MAXCOL)
	    (void)push_next_match(NULL, line);

	current_finished = TRUE;
	current_state_stored = FALSE;
	return 0;
    }

    /* if the next character is NUL, we will finish the line now */
    if (*(line + current_col) == NUL || *(line + current_col + 1) == NUL)
    {
	current_finished = TRUE;
	current_state_stored = FALSE;
    }

    /*
     * When in the previous column there was a match but it could not be used
     * (empty match or already matched in this column) need to try again in
     * the next column.
     */
    if (try_next_column)
    {
	next_match_idx = -1;
	try_next_column = FALSE;
    }

    /*
     * Repeat matching keywords and patterns, to find contained items at the
     * same column.  This stops when there are no extra matches at the current
     * column.
     */
    do
    {
	found_match = FALSE;
	syn_id = 0;

	/*
	 * 1. Check for a current state.
	 *    Only when there is no current state, or if the current state may
	 *    contain other things, we need to check for keywords and patterns.
	 */
	if (current_state.ga_len)
	    cur_si = &CUR_STATE(current_state.ga_len - 1);
	else
	    cur_si = NULL;

	if (cur_si == NULL || cur_si->si_cont_list != NULL)
	{
	    /*
	     * 2. Check for keywords, if on a keyword char after a non-keyword
	     *	  char.  Don't do this when syncing.
	     */
	    if (       !syncing
		    && (syn_buf->b_keywtab != NULL
			|| syn_buf->b_keywtab_ic != NULL)
		    && vim_iswordc_buf(line[current_col], syn_buf)
		    && (current_col == 0
			|| !vim_iswordc_buf(line[current_col - 1], syn_buf)))
	    {
		syn_id = check_keyword_id(line, (int)current_col,
					 &endcol, &flags, &next_list, cur_si);
		if (syn_id)
		{
		    if (push_current(KEYWORD_IDX) == OK)
		    {
			cur_si = &CUR_STATE(current_state.ga_len - 1);
			cur_si->si_m_startcol = current_col;
			cur_si->si_h_startcol = 0;	/* starts right away */
			cur_si->si_m_endcol = endcol;
			cur_si->si_h_endcol = endcol;
			cur_si->si_ends = TRUE;
			cur_si->si_end_idx = 0;
			cur_si->si_flags = flags;
			cur_si->si_id = syn_id;
			cur_si->si_trans_id = syn_id;
			if (flags & HL_TRANSP)
			{
			    if (current_state.ga_len < 2)
			    {
				cur_si->si_attr = 0;
				cur_si->si_trans_id = 0;
			    }
			    else
			    {
				cur_si->si_attr = CUR_STATE(
					current_state.ga_len - 2).si_attr;
				cur_si->si_trans_id = CUR_STATE(
					current_state.ga_len - 2).si_trans_id;
			    }

⌨️ 快捷键说明

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