Handle zero-length segments properly

master
Yevgen Muntyan 2006-08-29 04:36:40 -05:00
parent b37b8eac18
commit 55df4f1823
3 changed files with 178 additions and 34 deletions

View File

@ -73,6 +73,8 @@
(!(context)->definition->extend_parent || \
!(context)->all_ancestors_extend)
#define SEGMENT_END_AT_LINE_END(s) ((s)->context->definition->end_at_line_end)
#define CONTEXT_IS_SIMPLE(c) ((c)->definition->type == CONTEXT_TYPE_SIMPLE)
#define CONTEXT_IS_CONTAINER(c) ((c)->definition->type == CONTEXT_TYPE_CONTAINER)
#define SEGMENT_IS_INVALID(s) ((s)->context == NULL)
@ -374,6 +376,9 @@ static void erase_segments (GtkSourceContextEngine *ce,
gint start,
gint end,
Segment *hint);
static void segment_remove (GtkSourceContextEngine *ce,
Segment *segment);
static void find_insertion_place (Segment *segment,
gint offset,
Segment **parent,
@ -2480,6 +2485,9 @@ apply_match (Segment *state,
segment_extend (state, line->start_at + match_end);
apply_sub_patterns (state, line, regex, where);
*line_pos = match_end;
g_assert (state->end_at >= line->start_at + *line_pos);
return TRUE;
}
@ -3288,6 +3296,7 @@ segment_ends_here (Segment *state,
gint pos)
{
g_assert (SEGMENT_IS_CONTAINER (state));
return state->context->definition->u.start_end.end &&
regex_match (state->context->end,
line->text,
@ -3494,11 +3503,8 @@ next_segment (GtkSourceContextEngine *ce,
* Still, it may happen that parent context ends in
* the middle of the end regex match, apply_match()
* checks this. */
if (apply_match (state, line, &pos,
state->context->end,
SUB_PATTERN_WHERE_END))
if (apply_match (state, line, &pos, state->context->end, SUB_PATTERN_WHERE_END))
{
g_assert (state->end_at >= line->start_at + pos);
g_assert (pos <= line->length);
/* FIXME: if child may terminate parent */
*new_state = state->parent;
@ -3519,7 +3525,6 @@ next_segment (GtkSourceContextEngine *ce,
* check_line_end:
*
* @state: current state.
* @line: analyzed line.
* @hint: child of @state used in analyze_line() and next_segment().
*
* Closes the contexts that cannot contain end of lines if needed.
@ -3529,7 +3534,6 @@ next_segment (GtkSourceContextEngine *ce,
*/
static Segment *
check_line_end (Segment *state,
LineInfo *line,
Segment **hint)
{
Segment *current_segment;
@ -3543,29 +3547,17 @@ check_line_end (Segment *state,
terminating_segment = NULL;
current_segment = state;
do
while (current_segment)
{
if (current_segment->context->definition->end_at_line_end)
if (SEGMENT_END_AT_LINE_END (current_segment))
terminating_segment = current_segment;
else if (!ANCESTOR_CAN_END_CONTEXT(current_segment->context))
break;
current_segment = current_segment->parent;
}
while (current_segment &&
(ANCESTOR_CAN_END_CONTEXT (current_segment->context) ||
(terminating_segment && terminating_segment->parent == current_segment)));
if (terminating_segment)
{
/* We have found a context that ends here, so we close
* it and its descendants. */
current_segment = state;
do
{
g_assert (current_segment->end_at >= line->length);
current_segment = current_segment->parent;
}
while (current_segment != terminating_segment->parent);
*hint = terminating_segment;
return terminating_segment->parent;
}
@ -3575,6 +3567,69 @@ check_line_end (Segment *state,
}
}
static void
delete_zero_length_segments (GtkSourceContextEngine *ce,
GList *list,
Segment **hint)
{
while (list)
{
Segment *s = list->data;
if (s->start_at == s->end_at)
{
GList *l;
for (l = list->next; l != NULL; )
{
GList *next = l->next;
Segment *s2 = l->data;
gboolean child = FALSE;
while (s2)
{
if (s2 == s)
{
child = TRUE;
break;
}
s2 = s2->parent;
}
if (child)
list = g_list_delete_link (list, l);
l = next;
}
if (*hint)
{
Segment *s2 = *hint;
gboolean child = FALSE;
while (s2)
{
if (s2 == s)
{
child = TRUE;
break;
}
s2 = s2->parent;
}
if (child)
*hint = s->parent;
}
segment_remove (ce, s);
}
list = g_list_delete_link (list, list);
}
}
/**
* analyze_line:
*
@ -3594,6 +3649,7 @@ analyze_line (GtkSourceContextEngine *ce,
Segment **hint)
{
gint line_pos = 0;
GList *new_segments = NULL;
g_assert (SEGMENT_IS_CONTAINER (state));
g_assert (!(*hint) || (*hint)->parent == state);
@ -3607,8 +3663,14 @@ analyze_line (GtkSourceContextEngine *ce,
break;
g_assert (new_state != NULL);
g_assert (SEGMENT_IS_CONTAINER (new_state));
state = new_state;
g_assert (SEGMENT_IS_CONTAINER (state));
/* state may be extended later, so not all elements of new_segments
* really have zero length */
if (state->start_at == state->end_at)
new_segments = g_list_prepend (new_segments, state);
}
/* Extend current state to the end of line. */
@ -3618,14 +3680,21 @@ analyze_line (GtkSourceContextEngine *ce,
/* Verify if we need to close the context because we are at
* the end of the line. */
if (ANCESTOR_CAN_END_CONTEXT (state->context) ||
state->context->definition->end_at_line_end)
SEGMENT_END_AT_LINE_END (state))
{
state = check_line_end (state, line, hint);
state = check_line_end (state, hint);
}
/* Extend the segment to the beginning of next line. */
g_assert (SEGMENT_IS_CONTAINER (state));
segment_extend (state, NEXT_LINE_OFFSET (line));
/* if it's the last line, don't bother with zero length segments */
if (!line->eol_length)
g_list_free (new_segments);
else
delete_zero_length_segments (ce, new_segments, hint);
return state;
}

View File

@ -44,5 +44,9 @@
<style name="changelog:release" foreground="#0095ff" bold="true"/>
<style name="makefile:trailing-tab" background="pink"/>
<style name="makefile:trailing-tab" background="pink"/>
<!-- <style name="makefile:assignment-rhs" background="red"/>-->
<!-- <style name="makefile:assignment-lhs" background="blue"/>-->
<!-- <style name="makefile:prereq" background="yellow"/>-->
<!-- <style name="makefile:command" background="green"/>-->
</style-scheme>

View File

@ -2,13 +2,14 @@
<language id="makefile" _name="Makefile" version="2.0" _section="Sources"
mimetypes="text/x-makefile" globs="Makefile*">
<styles>
<style id="comment" name="Comment" map-to="def:comment"/>
<style id="function" name="Function" map-to="def:function"/>
<style id="string" name="String" map-to="def:string"/>
<style id="keyword" name="Keyword" map-to="def:keyword"/>
<style id="variable" name="Variable" map-to="def:data-type"/>
<style id="target" name="Target" map-to="def:function"/>
<style id="trailing-tab" name="Trailing Tab"/>
<style id="variable" name="Variable" map-to="def:data-type"/>
<style id="assignment-rhs" name="assignment-rhs"/>
<style id="assignment-lhs" name="assignment-lhs"/>
<style id="targets" name="targets" map-to="def:function"/>
<style id="prereq" name="prereq"/>
<style id="command" name="command"/>
<style id="trailing-tab" name="Trailing Tab"/>
<style id="function" name="function" map-to="def:function"/>
</styles>
<definitions>
@ -21,7 +22,77 @@
</include>
</context>
<context id="backtick-string" style-ref="function" end-at-line-end="true">
<start>`</start>
<end>`</end>
<include>
<context ref="def:escape"/>
<context ref="def:line-continue"/>
</include>
</context>
<context id="assignment-rhs" style-ref="assignment-rhs" end-at-line-end="true">
<start></start>
<include>
<context ref="def:line-continue"/>
<context ref="def:shell-like-comment"/>
<context ref="variable"/>
<context ref="def:string"/>
<context ref="def:single-quoted-string"/>
<context ref="backtick-string"/>
</include>
</context>
<context id="command" style-ref="command" extend-parent="false" end-at-line-end="true">
<start></start>
<include>
<context ref="def:line-continue"/>
<context ref="def:shell-like-comment"/>
<context ref="variable"/>
<context ref="def:string"/>
<context ref="def:single-quoted-string"/>
<context ref="backtick-string"/>
</include>
</context>
<context id="makefile">
<include>
<context ref="def:shebang"/>
<context ref="def:shell-like-comment"/>
<context id="assignment" end-at-line-end="true">
<start>^(\%{variable})\s*=</start>
<include>
<context sub-pattern="1" where="start" style-ref="assignment-lhs"/>
<context ref="assignment-rhs"/>
</include>
</context>
<context id="rule">
<start>^([^\t\:][^\:]*)\:</start>
<end>^(?!\t)</end>
<include>
<context sub-pattern="1" where="start" style-ref="targets"/>
<context id="prereq" end-at-line-end="true" style-ref="prereq">
<start>(?&lt;=:)</start>
<end>;</end>
<include>
<context ref="def:escape"/>
<context ref="def:line-continue"/>
<context ref="variable"/>
</include>
</context>
<context id="trailing-tab" style-ref="trailing-tab">
<match>^\t+$</match>
</context>
<context ref="command"/>
</include>
</context>
</include>
</context>
<!-- <context id="somecontext">
<include>
<context ref="def:shebang"/>
<context ref="def:shell-like-comment"/>
@ -111,6 +182,6 @@
<keyword>\.SUFFIXES</keyword>
</context>
</include>
</context>
</context>-->
</definitions>
</language>