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

📄 syntax.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
     * Also take cont_list, if there is none.
     * Don't do this for the matchgroup of a start or end pattern.
     */
    if ((spp->sp_flags & HL_TRANSP) && !(sip->si_flags & HL_MATCH))
    {
	if (idx == 0)
	{
	    sip->si_attr = 0;
	    sip->si_trans_id = 0;
	    if (sip->si_cont_list == NULL)
		sip->si_cont_list = ID_LIST_ALL;
	}
	else
	{
	    sip->si_attr = CUR_STATE(idx - 1).si_attr;
	    sip->si_trans_id = CUR_STATE(idx - 1).si_trans_id;
	    if (sip->si_cont_list == NULL)
		sip->si_cont_list = CUR_STATE(idx - 1).si_cont_list;
	}
    }
}

/*
 * Check the current stack for patterns with "keepend" flag.  Propagate the
 * match-end to contained items.
 */
    static void
check_keepend()
{
    int			i;
    int			maxend = MAXCOL;
    struct state_item	*sip;

    /*
     * This check can consume a lot of time; only do it from the level where
     * there really is a keepend.
     */
    if (keepend_level < 0)
	return;

    for (i = keepend_level; i < current_state.ga_len; ++i)
    {
	sip = &CUR_STATE(i);
	if (maxend < MAXCOL)
	{
	    if (sip->si_m_endcol > maxend)
		sip->si_m_endcol = maxend;
	    if (sip->si_h_endcol > maxend)
		sip->si_h_endcol = maxend;
	    if (sip->si_eoe_col > maxend)
		sip->si_eoe_col = maxend;
	    sip->si_ends = TRUE;
	}
	if (sip->si_ends && (sip->si_flags & HL_KEEPEND)
						 && maxend > sip->si_m_endcol)
	    maxend = sip->si_m_endcol;
    }
}

/*
 * Update an entry in the current_state stack for a start-skip-end pattern.
 * This finds the end of the current item, if it's in the current line.
 *
 * Return the flags for the matched END.
 */
    static void
update_si_end(sip, line, startcol)
    struct state_item	*sip;
    char_u		*line;
    int			startcol;   /* where to start searching for the end */
{
    char_u		*endp;
    char_u		*hl_endp;
    char_u		*end_endp;
    int			end_idx;

    /*
     * We need to find the end of the match.  It may continue in the next
     * line.
     */
    end_idx = 0;
    endp = find_endp(sip->si_idx, line + startcol,
	       startcol == 0, &hl_endp, &(sip->si_flags), &end_endp, &end_idx);
    if (endp == NULL)
    {
	/* continues on next line */
	if (SYN_ITEMS(syn_buf)[sip->si_idx].sp_flags & HL_ONELINE)
	{
	    sip->si_ends = TRUE;
	    sip->si_m_endcol = STRLEN(line) - 1;
	}
	else
	{
	    sip->si_ends = FALSE;
	    sip->si_m_endcol = MAXCOL;
	}
	sip->si_h_endcol = sip->si_m_endcol;
    }
    else
    {
	/* match within this line */
	sip->si_m_endcol = endp - line - 1;
	sip->si_h_endcol = hl_endp - line - 1;
	sip->si_ends = TRUE;
	sip->si_eoe_col = end_endp - line - 1;
	sip->si_end_idx = end_idx;
    }
    check_keepend();
}

/*
 * Add a new state to the current state stack.
 * Return FAIL if it's not possible (out of memory).
 */
    static int
push_current(idx)
    int	    idx;
{
    if (ga_grow(&current_state, 1) == FAIL)
	return FAIL;
    vim_memset(&CUR_STATE(current_state.ga_len), 0, sizeof(struct state_item));
    CUR_STATE(current_state.ga_len).si_idx = idx;
    ++current_state.ga_len;
    --current_state.ga_room;
    return OK;
}

/*
 * Remove a state from the current_state stack.
 */
    static void
pop_current()
{
    if (current_state.ga_len)
    {
	--current_state.ga_len;
	++current_state.ga_room;
    }
    /* after the end of a pattern, try matching a keyword or pattern */
    next_match_idx = -1;

    /* if first state with "keepend" is popped, reset keepend_level */
    if (keepend_level >= current_state.ga_len)
	keepend_level = -1;
}

/*
 * Find the end of a start/skip/end pattern match.
 */
    static char_u *
find_endp(idx, sstart, at_bol, hl_endp, flagsp, end_endp, end_idx)
    int	    idx;	/* index of the pattern */
    char_u  *sstart;	/* where to start looking for an END match */
    int	    at_bol;	/* if sstart is at begin-of-line */
    char_u  **hl_endp;	/* end column for highlighting */
    int	    *flagsp;	/* flags of matching END */
    char_u  **end_endp;	/* end of end pattern match */
    int	    *end_idx;	/* group ID for end pattern match, or 0 */
{
    char_u		*endp;		    /* end of highlighting */
    struct syn_pattern	*spp, *spp_skip;
    char_u		*p;		    /* end of match */
    int			start_idx;
    int			best_idx;
    char_u		*best_ptr;

    /*
     * Check for being called with a START pattern.
     * Can happen with a match that continues to the next line, because it
     * contained a region.
     */
    spp = &(SYN_ITEMS(syn_buf)[idx]);
    if (spp->sp_type != SPTYPE_START)
    {
	*hl_endp = sstart;
	return sstart;
    }

    /*
     * Find the SKIP or first END pattern after the last START pattern.
     */
    for (;;)
    {
	spp = &(SYN_ITEMS(syn_buf)[idx]);
	if (spp->sp_type != SPTYPE_START)
	    break;
	++idx;
    }

    /*
     *	Lookup the SKIP pattern (if present)
     */
    if (spp->sp_type == SPTYPE_SKIP)
    {
	spp_skip = spp;
	++idx;
    }
    else
	spp_skip = NULL;

    endp = sstart;	    /* start looking for a match at sstart */
    start_idx = idx;	    /* remember the first END pattern. */
    for (;;)
    {
	best_idx = -1;
	best_ptr = NULL;
	for (idx = start_idx; idx < syn_buf->b_syn_patterns.ga_len; ++idx)
	{
	    spp = &(SYN_ITEMS(syn_buf)[idx]);
	    if (spp->sp_type != SPTYPE_END)	/* past last END pattern */
		break;

	    reg_ic = spp->sp_ic;
	    if (syn_regexec(spp->sp_prog, endp, (at_bol && endp == sstart)))
	    {
		if (best_idx == -1 || spp->sp_prog->startp[0] < best_ptr)
		{
		    best_idx = idx;
		    best_ptr = spp->sp_prog->startp[0];
		}
	    }
	}

	/*
	 * If all end patterns have been tried, and there is no match, the
	 * item continues until end-of-line.
	 */
	if (best_idx == -1)
	    break;

	/*
	 * If the skip pattern matches before the end pattern,
	 * continue searching after the skip pattern.
	 */
	if (	   spp_skip != NULL
		&& (reg_ic = spp_skip->sp_ic,
			syn_regexec(spp_skip->sp_prog, endp,
						  (at_bol && endp == sstart)))
		&& spp_skip->sp_prog->startp[0] <= best_ptr)
	{
	    /* Add offset to skip pattern match */
	    p = syn_add_end_off(spp_skip, SPO_ME_OFF, 1);

	    /* take care of an empty match or negative offset */
	    if (p <= endp)
		++endp;
	    else if (p <= spp_skip->sp_prog->endp[0])
		endp = p;
	    else
		/* Be careful not to jump over the NUL at the end-of-line */
		for (endp = spp_skip->sp_prog->endp[0];
					     *endp != NUL && endp < p; ++endp)
		    ;

	    /* if skip pattern includes end-of-line, return here */
	    if (*endp == NUL)
		break;

	    continue;	    /* start with first end pattern again */
	}

	/*
	 * Match from start pattern to end pattern.
	 * Correct for match and highlight offset of end pattern.
	 */
	spp = &(SYN_ITEMS(syn_buf)[best_idx]);
	p = syn_add_end_off(spp, SPO_ME_OFF, 1);
	if (p < sstart)
	    p = sstart;

	endp = syn_add_end_off(spp, SPO_HE_OFF, 1);
	if (endp < sstart)
	    endp = sstart;
	if (endp > p)
	    endp = p;
	*end_endp = endp;

	/*
	 * If the end group is highlighted differently, adjust the pointers.
	 */
	if (spp->sp_syn_match_id != spp->sp_syn_id && spp->sp_syn_match_id != 0)
	{
	    *end_idx = best_idx;
	    if (spp->sp_off_flags & (1 << (SPO_RE_OFF + SPO_COUNT)))
		endp = spp->sp_prog->endp[0] + spp->sp_offsets[SPO_RE_OFF];
	    else
		endp = spp->sp_prog->startp[0] + spp->sp_offsets[SPO_RE_OFF];
	    if (endp < sstart)
		endp = sstart;
	    if (endp > p)
		endp = p;
	    p = endp;
	}
	else
	    *end_idx = 0;
	*hl_endp = endp;
	*flagsp = spp->sp_flags;

	return p;
    }

    return NULL;	/* no match for an END pattern in this line */
}

/*
 * Add offset to matched text for end of match or highlight.
 */
    static char_u *
syn_add_end_off(spp, idx, extra)
    struct syn_pattern	*spp;
    int			idx;
    int			extra;	    /* extra chars for offset to start */
{
    if (spp->sp_off_flags & (1 << idx))
	return spp->sp_prog->startp[0] + spp->sp_offsets[idx] + extra;
    return spp->sp_prog->endp[0] + spp->sp_offsets[idx];
}

/*
 * Add offset to matched text for start of match or highlight.
 */
    static char_u *
syn_add_start_off(spp, idx, extra)
    struct syn_pattern	*spp;
    int			idx;
    int			extra;	    /* extra chars for offset to end */
{
    if (spp->sp_off_flags & (1 << (idx + SPO_COUNT)))
	return spp->sp_prog->endp[0] + spp->sp_offsets[idx] + extra;
    return spp->sp_prog->startp[0] + spp->sp_offsets[idx];
}

/*
 * Check one position in a line for a matching keyword.
 * The caller must check if a keyword can start at startcol.
 * Return it's ID if found, 0 otherwise.
 */
    static int
check_keyword_id(line, startcol, endcol, flags, next_list, cur_si)
    char_u		*line;
    int			startcol;   /* position in line to check for keyword */
    int			*endcol;    /* last character of found keyword */
    int			*flags;	    /* flags of matching keyword */
    short		**next_list; /* next_list of matching keyword */
    struct state_item	*cur_si;    /* item at the top of the stack */
{
    struct keyentry *ktab;
    char_u	    *p;
    int		    round;
    int		    hash;
    int		    len;
    char_u	    keyword[MAXKEYWLEN + 1]; /* assume max. keyword len is 80 */

    /* Find first character after the keyword */
    p = line + startcol;
    for (len = 1; vim_iswordc_buf(p[len], syn_buf); ++len)
	;
    if (len > MAXKEYWLEN)
	return 0;

    /*
     * Must make a copy of the keyword, so we can add a NUL and make it
     * uppercase.
     */
    STRNCPY(keyword, p, len);
    keyword[len] = NUL;

    /*
     * Try twice:
     * 1. matching case
     * 2. ignoring case
     */
    for (round = 1; round <= 2; ++round)
    {
	if ((round == 1 ? syn_buf->b_keywtab : syn_buf->b_keywtab_ic) == NULL)
	    continue;
	p = keyword;
	hash = 0;
	if (round == 1)	/* match case */
	{
	    while (*p)
		hash += *p++;
	    ktab = syn_buf->b_keywtab[hash & KHASH_MASK];
	}
	else /* round == 2, ignore case */
	{
	    while (*p)
	    {
		hash += (*p = TO_LOWER(*p));
		++p;
	    }
	    ktab = syn_buf->b_keywtab_ic[hash & KHASH_MASK];
	}

	/*
	 * Find keywords that match.
	 * When current_next_list is non-zero accept only that group, otherwise:
	 *  Accept a not-contained keyword at toplevel.
	 *  Accept a keyword at other levels only if it is in the contains list.
	 */
	for ( ; ktab != NULL; ktab = ktab->next)
	    if (   STRCMP(keyword, ktab->keyword) == 0
		&& (   (current_next_list != 0
			&& in_id_list(current_next_list, ktab->syn_id,
				      ktab->syn_inc_lvl, 0))
		    || (current_next_list == 0
			&& ((cur_si == NULL && !(ktab->flags & HL_CONTAINED))
			    || (cur_si != NULL
				&& in_id_list(cur_si->si_cont_list,
					ktab->syn_id,
					ktab->syn_inc_lvl,
					ktab->flags & HL_CONTAINED))))))
	    {
		*endcol = startcol + len - 1;
		*flags = ktab->flags;
		*next_list = ktab->next_list;
		return ktab->syn_id;
	    }
    }
    return 0;
}

/*
 * Handle ":syntax case" command.
 */
/* ARGSUSED */
    static void
syn_cmd_case(eap, syncing)
    EXARG	*eap;
    int		syncing;	    /* not used */
{
    char_u	*arg = eap->arg;
   

⌨️ 快捷键说明

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