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

📄 syntax.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
			}
			else
			    cur_si->si_attr = syn_id2attr(syn_id);
			cur_si->si_cont_list = NULL;
			cur_si->si_next_list = next_list;
			check_keepend();
		    }
		    else
			vim_free(next_list);
		}
	    }

	    /*
	     * 3. Check for patterns (only if not found a keyword).
	     */
	    if (syn_id == 0 && syn_buf->b_syn_patterns.ga_len)
	    {
		/*
		 * If we didn't check for a match yet, or we are past it, check
		 * for any match with a pattern.
		 */
		if (next_match_idx < 0 || next_match_col < (int)current_col)
		{
		    /*
		     * Check all relevant patterns for a match at this
		     * position.
		     */
		    next_match_idx = 0;		/* no match in this line yet */
		    next_match_col = MAXCOL;	/* no match in this line yet */
		    for (idx = syn_buf->b_syn_patterns.ga_len; --idx >= 0; )
		    {
			spp = &(SYN_ITEMS(syn_buf)[idx]);
			if (	   spp->sp_syncing == syncing
				&& (spp->sp_type == SPTYPE_MATCH
				    || spp->sp_type == SPTYPE_START)
				&& ((current_next_list != 0
					&& in_id_list(current_next_list,
						spp->sp_syn_id,
						spp->sp_syn_inc_lvl, 0))
				    || (current_next_list == 0
					&& ((cur_si == NULL
					    && !(spp->sp_flags & HL_CONTAINED))
						|| (cur_si != NULL
					 && in_id_list(cur_si->si_cont_list,
						spp->sp_syn_id,
						spp->sp_syn_inc_lvl,
					     spp->sp_flags & HL_CONTAINED))))))
			{
			    int lc_col;

			    /* If we already tried matching in this line, and
			     * there isn't a match before next_match_col, skip
			     * this item. */
			    if (spp->sp_line_id == current_line_id
					&& spp->sp_startcol >= next_match_col)
				continue;
			    spp->sp_line_id = current_line_id;

			    lc_col = current_col - spp->sp_offsets[SPO_LC_OFF];
			    if (lc_col < 0)
				lc_col = 0;

			    reg_ic = spp->sp_ic;
			    if (!syn_regexec(spp->sp_prog, line + lc_col,
					     lc_col == 0))
			    {
				spp->sp_startcol = MAXCOL;
				continue;
			    }

			    /*
			     * Compute the first column of the match.
			     */
			    startcol = syn_add_start_off(spp,
						       SPO_MS_OFF, -1) - line;
			    if (startcol < 0)
				startcol = 0;
			    spp->sp_startcol = startcol;

			    /*
			     * If an existing match is better, skip this one.
			     */
			    if (startcol >= next_match_col)
				continue;

			    /*
			     * If we matched this pattern at this position
			     * before, skip it.  Must retry in the next
			     * column, because it may match from there..
			     */
			    if (did_match_already(idx))
			    {
				try_next_column = TRUE;
				continue;
			    }

			    endp = spp->sp_prog->endp[0];

			    /* Compute the highlight start. */
			    hl_startcol = syn_add_start_off(spp,
						       SPO_HS_OFF, -1) - line;

			    /* Compute the region start. */
			    /* Default is to use the end of the match. */
			    if (spp->sp_off_flags & (1 << SPO_RS_OFF))
				eos_col = (spp->sp_prog->startp[0] - line)
					    + spp->sp_offsets[SPO_RS_OFF] - 1;
			    else
				eos_col = (endp - line) - 1
						+ spp->sp_offsets[SPO_RS_OFF];

			    /*
			     * If this is a oneline, the end must be found
			     * in the same line too.
			     */
			    flags = 0;
			    eoep = line;	/* avoid warning */
			    end_idx = 0;
			    if (spp->sp_type == SPTYPE_START
				    && (spp->sp_flags & HL_ONELINE))
				endp = find_endp(idx, endp, endp == line,
					&hl_endp, &flags, &eoep, &end_idx);

			    /*
			     * For a "match" the size must be > 0 after the
			     * end offset needs has been added.  Except when
			     * syncing.
			     */
			    else if (spp->sp_type == SPTYPE_MATCH)
			    {
				hl_endp = syn_add_end_off(spp, SPO_HE_OFF, 0);
				endp = syn_add_end_off(spp, SPO_ME_OFF, 0);
				if (endp + syncing <= line + startcol)
				{
				    /*
				     * If an empty string is matched, may need
				     * to try matching again at next column.
				     */
				    if (spp->sp_prog->startp[0] ==
							spp->sp_prog->endp[0])
					try_next_column = TRUE;
				    continue;
				}
			    }

			    /* keep the best match so far in next_match_* */
			    if (endp != NULL)
			    {
				if (hl_startcol < startcol)
				    hl_startcol = startcol;
				if (hl_endp == NULL || hl_endp > endp)
				    hl_endp = endp;

				next_match_idx = idx;
				next_match_col = startcol;
				next_match_m_endcol = endp - line;
				next_match_h_endcol = hl_endp - line;
				next_match_h_startcol = hl_startcol;
				next_match_flags = flags;
				next_match_eos_col = eos_col;
				next_match_eoe_col = eoep - line;
				next_match_end_idx = end_idx;
			    }
			}
		    }
		}

		/*
		 * If we found a match at the current column, use it.
		 */
		if (next_match_idx >= 0 && next_match_col == (int)current_col)
		{
		    cur_si = push_next_match(cur_si, line);
		    found_match = TRUE;
		}
	    }
	}

	/*
	 * Handle searching for nextgroup match.
	 */
	if (current_next_list)
	{
	    /*
	     * If a nextgroup was not found, continue looking for one if:
	     * - this is an empty line and the "skipempty" option was given
	     * - we are on white space and the "skipwhite" option was given
	     */
	    if (!found_match
		    && (   ((current_next_flags & HL_SKIPWHITE)
			    && vim_iswhite(line[current_col]))
			|| ((current_next_flags & HL_SKIPEMPTY)
			    && *line == NUL)))
		break;

	    /*
	     * If a nextgroup was found: Use it, and continue looking for
	     * contained matches.
	     * If a nextgroup was not found: Continue looking for a normal
	     * match.
	     */
	    current_next_list = NULL;
	    next_match_idx = -1;
	    found_match = TRUE;
	}

    } while (found_match);

    /*
     * Use attributes from the current state, if within its highlighting.
     * If not, use attributes from the current-but-one state, etc.
     */
    current_attr = 0;
    current_id = 0;
    current_trans_id = 0;
    if (cur_si != NULL)
    {
	for (idx = current_state.ga_len - 1; idx >= 0; --idx)
	{
	    sip = &CUR_STATE(idx);
	    if ((int)current_col >= sip->si_h_startcol
				      && (int)current_col <= sip->si_h_endcol)
	    {
		current_attr = sip->si_attr;
		current_id = sip->si_id;
		current_trans_id = sip->si_trans_id;
		break;
	    }
	}

	/*
	 * Check for end of current state (and the states before it) at the
	 * next column.  Don't do this for syncing, because we would miss a
	 * single character match.
	 */
	if (!syncing)
	{
	    ++current_col;
	    check_state_ends(line);
	    --current_col;
	}
    }

    /* nextgroup ends at end of line, unless "skipnl" or "skipemtpy" present */
    if (current_next_list != NULL
	    && line[current_col + 1] == NUL
	    && !(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY)))
	current_next_list = NULL;

    return current_attr;
}

/*
 * Check if we already matched pattern "idx" at the current column.
 */
    static int
did_match_already(idx)
    int	    idx;
{
    int		i;

    for (i = current_state.ga_len; --i >= 0; )
    {
	if (CUR_STATE(i).si_m_startcol == (int)current_col
		&& CUR_STATE(i).si_m_lnum == (int)current_lnum
		&& CUR_STATE(i).si_idx == idx)
	    return TRUE;
    }
    return FALSE;
}

/*
 * Push the next match onto the stack.
 */
    static struct state_item *
push_next_match(cur_si, line)
    struct state_item	*cur_si;
    char_u		*line;
{
    struct syn_pattern	*spp;

    spp = &(SYN_ITEMS(syn_buf)[next_match_idx]);

    /*
     * Push the item in current_state stack;
     */
    if (push_current(next_match_idx) == OK)
    {
	/*
	 * If it's a start-skip-end type that crosses lines, figure out how
	 * much it continues in this line.  Otherwise just fill in the length.
	 */
	cur_si = &CUR_STATE(current_state.ga_len - 1);
	cur_si->si_h_startcol = next_match_h_startcol;
	cur_si->si_m_startcol = current_col;
	cur_si->si_m_lnum = current_lnum;
	cur_si->si_flags = spp->sp_flags;
	cur_si->si_next_list = spp->sp_next_list;
	if (spp->sp_type == SPTYPE_START && !(spp->sp_flags & HL_ONELINE))
	{
	    update_si_end(cur_si, line, next_match_m_endcol);
	}
	else
	{
	    cur_si->si_m_endcol = next_match_m_endcol - 1;
	    cur_si->si_h_endcol = next_match_h_endcol - 1;
	    cur_si->si_ends = TRUE;
	    cur_si->si_flags |= next_match_flags;
	    cur_si->si_eoe_col = next_match_eoe_col;
	    cur_si->si_end_idx = next_match_end_idx;
	}
	if (keepend_level < 0 && (cur_si->si_flags & HL_KEEPEND))
	    keepend_level = current_state.ga_len - 1;
	check_keepend();
	update_si_attr(current_state.ga_len - 1);

	/*
	 * If the start pattern has another highlight group, push another item
	 * on the stack for the start pattern.
	 */
	if (	   spp->sp_type == SPTYPE_START
		&& spp->sp_syn_match_id != 0
		&& spp->sp_syn_id != spp->sp_syn_match_id
		&& push_current(next_match_idx) == OK)
	{
	    cur_si = &CUR_STATE(current_state.ga_len - 1);
	    cur_si->si_h_startcol = next_match_h_startcol;
	    cur_si->si_m_startcol = current_col;
	    cur_si->si_m_lnum = current_lnum;
	    cur_si->si_m_endcol = next_match_eos_col;
	    cur_si->si_h_endcol = next_match_eos_col;
	    cur_si->si_ends = TRUE;
	    cur_si->si_end_idx = 0;
	    cur_si->si_flags = HL_MATCH;
	    cur_si->si_next_list = NULL;
	    check_keepend();
	    update_si_attr(current_state.ga_len - 1);
	}
    }

    next_match_idx = -1;	/* try other match next time */

    return cur_si;
}

/*
 * Check for end of current state (and the states before it).
 */
    static void
check_state_ends(line)
    char_u		*line;
{
    struct state_item	*cur_si;

    cur_si = &CUR_STATE(current_state.ga_len - 1);
    for (;;)
    {
	if (cur_si->si_m_endcol < (int)current_col && cur_si->si_ends)
	{
	    /*
	     * If there is an end pattern group ID, highlight the end pattern
	     * now.  No need to pop the current item from the stack.
	     * Only do this if the end pattern continuous beyond the current
	     * position.
	     */
	    if (cur_si->si_end_idx && cur_si->si_eoe_col >= (int)current_col)
	    {
		cur_si->si_idx = cur_si->si_end_idx;
		cur_si->si_end_idx = 0;
		cur_si->si_m_endcol = cur_si->si_eoe_col;
		cur_si->si_h_endcol = cur_si->si_eoe_col;
		cur_si->si_flags |= HL_MATCH;
		update_si_attr(current_state.ga_len - 1);
		break;
	    }
	    else
	    {
		/* handle next_list, unless at end of line and no "skipnl" or
		 * "skipempty" */
		current_next_list = cur_si->si_next_list;
		current_next_flags = cur_si->si_flags;
		if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))
			&& line[current_col] == NUL)
		    current_next_list = NULL;
		pop_current();

		if (current_state.ga_len == 0)
		    break;
		cur_si = &CUR_STATE(current_state.ga_len - 1);

		/*
		 * Only for a region the search for the end continues after
		 * the end of the contained item.  If the contained match
		 * included the end-of-line, break here, the region continues.
		 * Don't do this when "keepend" is used.
		 */
		if (SYN_ITEMS(syn_buf)[cur_si->si_idx].sp_type == SPTYPE_START
			     && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND)))
		{
		    update_si_end(cur_si, line, (int)current_col);
		    if (current_next_flags & HL_HAS_EOL)
			break;
		}
	    }
	}
	else
	    break;
    }
}

/*
 * Update an entry in the current_state stack for a match or region.  This
 * fills in si_attr and si_cont_list.
 */
    static void
update_si_attr(idx)
    int	    idx;
{
    struct state_item	*sip = &CUR_STATE(idx);
    struct syn_pattern	*spp;

    spp = &(SYN_ITEMS(syn_buf)[sip->si_idx]);
    if (sip->si_flags & HL_MATCH)
	sip->si_id = spp->sp_syn_match_id;
    else
	sip->si_id = spp->sp_syn_id;
    sip->si_attr = syn_id2attr(sip->si_id);
    sip->si_trans_id = sip->si_id;
    if (sip->si_flags & HL_MATCH)
	sip->si_cont_list = NULL;
    else
	sip->si_cont_list = spp->sp_cont_list;

    /*
     * For transparent items, take attr from outer item.

⌨️ 快捷键说明

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