📄 syntax.c
字号:
}
/*
* 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(¤t_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(¤t_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(¤t_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(¤t_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 + -