📄 syntax.c
字号:
}
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 + -