2005-10-13 07:08:18 -07:00
|
|
|
/*
|
|
|
|
* moohighlighter.c
|
|
|
|
*
|
2006-02-23 06:03:17 -08:00
|
|
|
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
2005-10-13 07:08:18 -07:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* See COPYING file that comes with this distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MOOEDIT_COMPILATION
|
|
|
|
#include "mooedit/moohighlighter.h"
|
|
|
|
#include "mooedit/moolang-rules.h"
|
|
|
|
#include "mooedit/gtksourceiter.h"
|
2005-12-10 20:25:13 -08:00
|
|
|
#include "mooedit/mootext-private.h"
|
2005-10-13 07:08:18 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
#define IDLE_HIGHLIGHT_PRIORITY GTK_TEXT_VIEW_PRIORITY_VALIDATE
|
2005-11-22 10:39:05 -08:00
|
|
|
#define IDLE_HIGHLIGHT_TIME 30
|
|
|
|
#define COMPUTE_NOW_TIME 20
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
|
|
|
|
static MooSyntaxTag *iter_get_syntax_tag (const GtkTextIter *iter);
|
|
|
|
|
|
|
|
static GtkTextTag *moo_syntax_tag_new (CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule);
|
|
|
|
static GtkTextTag *create_tag (MooHighlighter *hl,
|
|
|
|
CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule);
|
|
|
|
static GtkTextTag *get_syntax_tag (MooHighlighter *hl,
|
|
|
|
CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule);
|
|
|
|
|
|
|
|
static CtxNode *ctx_node_new (MooHighlighter *hl,
|
|
|
|
CtxNode *parent,
|
|
|
|
MooContext *context,
|
|
|
|
gboolean create_tag);
|
|
|
|
static void ctx_node_free (CtxNode *node,
|
|
|
|
GtkTextTagTable *table);
|
|
|
|
static CtxNode *get_next_node (MooHighlighter *hl,
|
|
|
|
CtxNode *node,
|
|
|
|
MooRule *rule);
|
|
|
|
static CtxNode *get_line_end_node (MooHighlighter *hl,
|
|
|
|
CtxNode *node);
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
static CtxNode *hl_compute_line (MooHighlighter *hl,
|
2005-10-13 07:08:18 -07:00
|
|
|
Line *line,
|
|
|
|
MatchData *data,
|
2005-11-22 10:39:05 -08:00
|
|
|
CtxNode *node,
|
|
|
|
gboolean apply_tags);
|
|
|
|
static gboolean hl_compute_range (MooHighlighter *hl,
|
2005-10-13 07:08:18 -07:00
|
|
|
Interval *lines,
|
|
|
|
gboolean apply_tags,
|
|
|
|
int time);
|
|
|
|
|
|
|
|
|
|
|
|
/* MOO_TYPE_SYNTAX_TAG */
|
|
|
|
G_DEFINE_TYPE (MooSyntaxTag, moo_syntax_tag, GTK_TYPE_TEXT_TAG)
|
|
|
|
|
|
|
|
|
|
|
|
// static void
|
|
|
|
// moo_syntax_tag_finalize (GObject *object)
|
|
|
|
// {
|
|
|
|
// g_free (MOO_SYNTAX_TAG(object)->stack);
|
|
|
|
// G_OBJECT_CLASS(moo_syntax_tag_parent_class)->finalize (object);
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
moo_syntax_tag_class_init (G_GNUC_UNUSED MooSyntaxTagClass *klass)
|
|
|
|
{
|
|
|
|
// G_OBJECT_CLASS(klass)->finalize = moo_syntax_tag_finalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
moo_syntax_tag_init (MooSyntaxTag *tag)
|
|
|
|
{
|
|
|
|
tag->ctx_node = NULL;
|
|
|
|
tag->match_node = NULL;
|
|
|
|
tag->rule = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_tag (G_GNUC_UNUSED gpointer rule,
|
|
|
|
GtkTextTag *tag,
|
|
|
|
GtkTextTagTable *table)
|
|
|
|
{
|
|
|
|
gtk_text_tag_table_remove (table, tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ctx_node_free (CtxNode *node,
|
|
|
|
GtkTextTagTable *table)
|
|
|
|
{
|
|
|
|
if (table)
|
|
|
|
g_hash_table_foreach (node->match_tags, (GHFunc) remove_tag, table);
|
|
|
|
|
|
|
|
g_hash_table_destroy (node->match_tags);
|
|
|
|
g_hash_table_destroy (node->children);
|
|
|
|
g_slist_free (node->child_tags);
|
|
|
|
|
|
|
|
if (node->context_tag && table)
|
|
|
|
gtk_text_tag_table_remove (table, node->context_tag);
|
|
|
|
|
|
|
|
g_free (node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_highlighter_destroy (MooHighlighter *hl,
|
|
|
|
gboolean delete_tags)
|
|
|
|
{
|
|
|
|
GtkTextTagTable *table = NULL;
|
|
|
|
|
|
|
|
g_return_if_fail (hl != NULL);
|
|
|
|
|
|
|
|
if (delete_tags)
|
|
|
|
table = gtk_text_buffer_get_tag_table (hl->buffer);
|
|
|
|
|
|
|
|
g_slist_foreach (hl->nodes, (GFunc) ctx_node_free, table);
|
|
|
|
|
|
|
|
if (hl->lang)
|
|
|
|
moo_lang_unref (hl->lang);
|
|
|
|
if (hl->idle)
|
|
|
|
g_source_remove (hl->idle);
|
2005-11-22 10:39:05 -08:00
|
|
|
if (hl->apply_idle)
|
|
|
|
g_source_remove (hl->apply_idle);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
g_free (hl);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-17 01:12:12 -08:00
|
|
|
GtkTextTag *
|
|
|
|
_moo_text_iter_get_syntax_tag (const GtkTextIter *iter)
|
|
|
|
{
|
2005-11-22 10:39:05 -08:00
|
|
|
return (GtkTextTag*) iter_get_syntax_tag (iter);
|
2005-11-17 01:12:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-13 07:08:18 -07:00
|
|
|
static MooSyntaxTag*
|
|
|
|
iter_get_syntax_tag (const GtkTextIter *iter)
|
|
|
|
{
|
|
|
|
MooSyntaxTag *tag = NULL;
|
|
|
|
GSList *l;
|
|
|
|
GSList *list = gtk_text_iter_get_tags (iter);
|
|
|
|
|
|
|
|
for (l = list; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
if (MOO_IS_SYNTAX_TAG (l->data))
|
|
|
|
{
|
2005-12-13 04:44:02 -08:00
|
|
|
#ifndef MOO_DEBUG
|
2005-10-13 07:08:18 -07:00
|
|
|
tag = l->data;
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
g_assert (tag == NULL);
|
|
|
|
tag = l->data;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free (list);
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MooContext*
|
|
|
|
_moo_text_iter_get_context (const GtkTextIter *iter)
|
|
|
|
{
|
|
|
|
MooSyntaxTag *tag = iter_get_syntax_tag (iter);
|
|
|
|
return tag ? tag->ctx_node->ctx : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
apply_tag (MooHighlighter *hl,
|
2005-11-22 10:39:05 -08:00
|
|
|
Line *line,
|
2005-10-13 07:08:18 -07:00
|
|
|
CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule,
|
|
|
|
const GtkTextIter *start,
|
2005-11-22 10:39:05 -08:00
|
|
|
const GtkTextIter *end)
|
2005-10-13 07:08:18 -07:00
|
|
|
{
|
|
|
|
GtkTextTag *tag = get_syntax_tag (hl, ctx_node, match_node, rule);
|
|
|
|
|
|
|
|
g_assert (!tag || (MOO_IS_SYNTAX_TAG (tag) && MOO_SYNTAX_TAG(tag)->rule == rule));
|
|
|
|
g_assert (!tag || MOO_SYNTAX_TAG(tag)->match_node != NULL || MOO_SYNTAX_TAG(tag)->ctx_node != hl->root);
|
|
|
|
|
|
|
|
if (!gtk_text_iter_compare (start, end))
|
|
|
|
return;
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
g_assert (iter_get_syntax_tag (start) == NULL);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
if (tag)
|
2005-11-22 10:39:05 -08:00
|
|
|
{
|
2005-11-23 03:10:03 -08:00
|
|
|
line->hl_info->tags = g_slist_prepend (line->hl_info->tags, g_object_ref (tag));
|
2005-11-22 20:56:30 -08:00
|
|
|
hl->last_tag = tag;
|
2005-10-13 07:08:18 -07:00
|
|
|
_moo_text_buffer_apply_syntax_tag (MOO_TEXT_BUFFER (hl->buffer), tag, start, end);
|
2005-11-22 10:39:05 -08:00
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-13 23:01:40 -08:00
|
|
|
#if !GTK_CHECK_VERSION(2,8,0)
|
|
|
|
static void
|
|
|
|
check_last_tag (MooHighlighter *hl)
|
|
|
|
{
|
|
|
|
if (hl->last_tag && hl->need_last_tag)
|
|
|
|
{
|
|
|
|
gboolean fg_set;
|
|
|
|
g_object_get (hl->last_tag, "foreground-set", &fg_set, NULL);
|
|
|
|
g_object_set (hl->last_tag, "foreground-set", fg_set, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
hl->last_tag = NULL;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define check_last_tag(hl)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2005-10-13 07:08:18 -07:00
|
|
|
MooHighlighter*
|
|
|
|
moo_highlighter_new (GtkTextBuffer *buffer,
|
|
|
|
LineBuffer *line_buf,
|
|
|
|
MooLang *lang)
|
|
|
|
{
|
|
|
|
MooHighlighter *hl;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
|
|
|
|
|
|
|
hl = g_new0 (MooHighlighter, 1);
|
|
|
|
hl->lang = lang ? moo_lang_ref (lang) : NULL;
|
|
|
|
hl->buffer = buffer;
|
|
|
|
hl->line_buf = line_buf;
|
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
if (gtk_check_version (2, 8, 0))
|
|
|
|
hl->need_last_tag = TRUE;
|
|
|
|
|
2005-10-13 07:08:18 -07:00
|
|
|
return hl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GtkTextTag*
|
|
|
|
moo_syntax_tag_new (CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule)
|
|
|
|
{
|
|
|
|
GtkTextTag *tag = g_object_new (MOO_TYPE_SYNTAX_TAG, NULL);
|
|
|
|
|
|
|
|
g_assert (ctx_node != NULL);
|
|
|
|
g_assert (rule != NULL || match_node == NULL);
|
|
|
|
g_assert (rule == NULL || match_node != NULL);
|
|
|
|
|
|
|
|
MOO_SYNTAX_TAG(tag)->ctx_node = ctx_node;
|
|
|
|
MOO_SYNTAX_TAG(tag)->match_node = match_node;
|
|
|
|
MOO_SYNTAX_TAG(tag)->rule = rule;
|
|
|
|
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GtkTextTag*
|
|
|
|
create_tag (MooHighlighter *hl,
|
|
|
|
CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule)
|
|
|
|
{
|
2005-12-13 23:05:11 -08:00
|
|
|
GtkTextTag *tag;
|
|
|
|
|
|
|
|
if (!ctx_node->parent && !match_node && !rule)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
tag = moo_syntax_tag_new (ctx_node, match_node, rule);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
gtk_text_tag_table_add (gtk_text_buffer_get_tag_table (hl->buffer), tag);
|
|
|
|
g_object_unref (tag);
|
|
|
|
|
|
|
|
_moo_lang_set_tag_style (rule ? rule->context->lang : ctx_node->ctx->lang,
|
|
|
|
tag,
|
|
|
|
rule ? rule->context : ctx_node->ctx,
|
2005-10-16 22:23:40 -07:00
|
|
|
rule, NULL);
|
2005-10-13 07:08:18 -07:00
|
|
|
ctx_node->child_tags = g_slist_prepend (ctx_node->child_tags, tag);
|
|
|
|
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static GtkTextTag*
|
|
|
|
get_syntax_tag (MooHighlighter *hl,
|
|
|
|
CtxNode *ctx_node,
|
|
|
|
CtxNode *match_node,
|
|
|
|
MooRule *rule)
|
|
|
|
{
|
|
|
|
GtkTextTag *tag;
|
|
|
|
|
|
|
|
g_assert (ctx_node != NULL);
|
|
|
|
g_assert ((!match_node && !rule) || (match_node && rule));
|
|
|
|
|
|
|
|
if (!match_node)
|
|
|
|
return ctx_node->context_tag;
|
|
|
|
|
|
|
|
tag = g_hash_table_lookup (match_node->match_tags, rule);
|
|
|
|
|
|
|
|
if (!tag)
|
|
|
|
{
|
|
|
|
tag = create_tag (hl, ctx_node, match_node, rule);
|
|
|
|
g_hash_table_insert (match_node->match_tags, rule, tag);
|
|
|
|
}
|
|
|
|
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static CtxNode*
|
|
|
|
ctx_node_new (MooHighlighter *hl,
|
|
|
|
CtxNode *parent,
|
|
|
|
MooContext *context,
|
|
|
|
gboolean create_text_tag)
|
|
|
|
{
|
|
|
|
CtxNode *node = g_new0 (CtxNode, 1);
|
|
|
|
|
|
|
|
g_return_val_if_fail (context != NULL, NULL);
|
|
|
|
|
|
|
|
node->ctx = context;
|
|
|
|
node->parent = parent;
|
|
|
|
|
|
|
|
node->match_tags = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
|
|
node->children = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
node->depth = parent->depth + 1;
|
|
|
|
else
|
|
|
|
node->depth = 0;
|
|
|
|
|
|
|
|
if (create_text_tag)
|
|
|
|
node->context_tag = create_tag (hl, node, NULL, NULL);
|
|
|
|
|
|
|
|
hl->nodes = g_slist_prepend (hl->nodes, node);
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static CtxNode*
|
|
|
|
get_next_node (MooHighlighter *hl,
|
|
|
|
CtxNode *node,
|
|
|
|
MooRule *rule)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
CtxNode *next;
|
|
|
|
|
|
|
|
g_assert (rule != NULL);
|
|
|
|
|
|
|
|
if ((next = g_hash_table_lookup (node->children, rule)))
|
|
|
|
return next;
|
|
|
|
|
|
|
|
switch (rule->exit.type)
|
|
|
|
{
|
|
|
|
case MOO_CONTEXT_STAY:
|
|
|
|
next = node;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MOO_CONTEXT_POP:
|
|
|
|
for (i = 0, next = node; next->parent != NULL && i < rule->exit.num;
|
|
|
|
++i, next = next->parent);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MOO_CONTEXT_SWITCH:
|
|
|
|
next = ctx_node_new (hl, node, rule->exit.ctx, TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (next != NULL);
|
|
|
|
g_hash_table_insert (node->children, rule, next);
|
|
|
|
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static CtxNode*
|
|
|
|
get_line_end_node (MooHighlighter *hl,
|
|
|
|
CtxNode *node)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
CtxNode *next = NULL;
|
|
|
|
MooContext *ctx = node->ctx;
|
|
|
|
|
|
|
|
if (node->line_end)
|
|
|
|
return node->line_end;
|
|
|
|
|
|
|
|
switch (ctx->line_end.type)
|
|
|
|
{
|
|
|
|
case MOO_CONTEXT_STAY:
|
|
|
|
next = node;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MOO_CONTEXT_POP:
|
|
|
|
for (i = 0, next = node; next->parent != NULL && i < ctx->line_end.num;
|
|
|
|
++i, next = next->parent);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MOO_CONTEXT_SWITCH:
|
|
|
|
next = ctx_node_new (hl, node, ctx->line_end.ctx, TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (next != NULL);
|
|
|
|
node->line_end = next;
|
|
|
|
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static CtxNode*
|
|
|
|
get_next_line_node (MooHighlighter *hl,
|
|
|
|
Line *line)
|
|
|
|
{
|
|
|
|
HLInfo *info = line->hl_info;
|
|
|
|
CtxNode *last_node;
|
|
|
|
|
|
|
|
if (!info->n_segments)
|
|
|
|
{
|
|
|
|
last_node = info->start_node;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Segment *last = &info->segments[info->n_segments - 1];
|
|
|
|
|
|
|
|
if (last->rule)
|
2005-11-10 07:45:26 -08:00
|
|
|
{
|
|
|
|
if (last->rule->include_eol)
|
|
|
|
return get_next_node (hl, last->ctx_node, last->rule);
|
|
|
|
else
|
|
|
|
last_node = get_next_node (hl, last->ctx_node, last->rule);
|
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
else
|
2005-11-10 07:45:26 -08:00
|
|
|
{
|
2005-10-13 07:08:18 -07:00
|
|
|
last_node = last->ctx_node;
|
2005-11-10 07:45:26 -08:00
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
g_assert (last_node != NULL);
|
|
|
|
return get_line_end_node (hl, last_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
static CtxNode *
|
2005-10-13 07:08:18 -07:00
|
|
|
hl_compute_line (MooHighlighter *hl,
|
|
|
|
Line *line,
|
|
|
|
MatchData *data,
|
2005-11-22 10:39:05 -08:00
|
|
|
CtxNode *node,
|
|
|
|
gboolean apply_tags)
|
2005-10-13 07:08:18 -07:00
|
|
|
{
|
2005-11-22 10:39:05 -08:00
|
|
|
MooRule *matched_rule;
|
2005-10-13 07:08:18 -07:00
|
|
|
MatchResult result;
|
|
|
|
|
2005-11-24 00:34:02 -08:00
|
|
|
if (apply_tags && line->hl_info->tags)
|
2005-11-22 10:39:05 -08:00
|
|
|
{
|
|
|
|
GSList *tags = line->hl_info->tags;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
line->hl_info->tags = NULL;
|
|
|
|
|
2005-11-24 00:34:02 -08:00
|
|
|
if (!gtk_text_iter_ends_line (&data->start_iter))
|
|
|
|
{
|
|
|
|
GtkTextIter end = data->start_iter;
|
2005-12-10 20:23:32 -08:00
|
|
|
GSList *l;
|
|
|
|
|
2005-11-24 00:34:02 -08:00
|
|
|
gtk_text_iter_forward_to_line_end (&end);
|
2005-11-22 10:39:05 -08:00
|
|
|
|
2005-12-10 20:23:32 -08:00
|
|
|
for (l = tags; l; l = l->next)
|
|
|
|
gtk_text_buffer_remove_tag (hl->buffer, l->data, &data->start_iter, &end);
|
2005-11-22 10:39:05 -08:00
|
|
|
}
|
2005-12-10 20:23:32 -08:00
|
|
|
|
|
|
|
g_slist_foreach (tags, (GFunc) g_object_unref, NULL);
|
|
|
|
g_slist_free (tags);
|
2005-11-22 10:39:05 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (!gtk_text_iter_ends_line (&data->start_iter))
|
2005-10-13 07:08:18 -07:00
|
|
|
{
|
2005-11-22 10:39:05 -08:00
|
|
|
if ((matched_rule = moo_rule_array_match (node->ctx->rules, data, &result)))
|
|
|
|
{
|
|
|
|
CtxNode *match_node, *next_node;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (result.match_offset < 0)
|
|
|
|
result.match_offset = g_utf8_pointer_to_offset (data->start, result.match_start);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (result.match_len < 0)
|
|
|
|
result.match_len = g_utf8_pointer_to_offset (result.match_start, result.match_end);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
if (result.match_offset)
|
|
|
|
moo_line_add_segment (line, result.match_offset, node, NULL, NULL);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
next_node = get_next_node (hl, node, matched_rule);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (matched_rule->flags & MOO_RULE_INCLUDE_INTO_NEXT)
|
|
|
|
match_node = next_node;
|
|
|
|
else
|
|
|
|
match_node = node;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
moo_line_add_segment (line, result.match_len, match_node, node, matched_rule);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (apply_tags)
|
|
|
|
{
|
|
|
|
GtkTextIter m_start = data->start_iter, m_end;
|
2005-11-22 20:56:30 -08:00
|
|
|
|
|
|
|
if (result.match_offset)
|
|
|
|
gtk_text_iter_forward_chars (&m_start, result.match_offset);
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
m_end = m_start;
|
|
|
|
gtk_text_iter_forward_chars (&m_end, result.match_len);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
if (result.match_offset)
|
|
|
|
apply_tag (hl, line, node, NULL, NULL, &data->start_iter, &m_start);
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
apply_tag (hl, line, match_node, node, matched_rule, &m_start, &m_end);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
moo_match_data_set_start (data, &m_end, result.match_end,
|
|
|
|
data->start_offset + result.match_offset + result.match_len);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
moo_match_data_set_start (data, NULL, result.match_end,
|
|
|
|
data->start_offset + result.match_offset + result.match_len);
|
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
node = next_node;
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-11-22 10:39:05 -08:00
|
|
|
moo_line_add_segment (line, -1, node, NULL, NULL);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (apply_tags)
|
|
|
|
{
|
|
|
|
GtkTextIter eol = data->start_iter;
|
|
|
|
gtk_text_iter_forward_to_line_end (&eol);
|
|
|
|
apply_tag (hl, line, node, NULL, NULL, &data->start_iter, &eol);
|
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
break;
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (apply_tags)
|
|
|
|
line->hl_info->tags_applied = TRUE;
|
|
|
|
|
|
|
|
return get_next_line_node (hl, line);
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
static gboolean
|
2005-10-13 07:08:18 -07:00
|
|
|
hl_compute_range (MooHighlighter *hl,
|
|
|
|
Interval *lines,
|
|
|
|
gboolean apply_tags,
|
|
|
|
int time)
|
|
|
|
{
|
|
|
|
GtkTextIter iter;
|
|
|
|
CtxNode *node;
|
2005-11-22 10:39:05 -08:00
|
|
|
int line_no;
|
2005-10-13 07:08:18 -07:00
|
|
|
GTimer *timer = NULL;
|
|
|
|
double secs = ((double) time) / 1000;
|
2005-11-20 23:48:11 -08:00
|
|
|
gboolean done = FALSE;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
g_assert (!hl->line_buf->invalid.empty);
|
|
|
|
g_assert (lines->first == hl->line_buf->invalid.first);
|
|
|
|
|
|
|
|
if (time > 0)
|
|
|
|
timer = g_timer_new ();
|
|
|
|
|
|
|
|
if (lines->first == 0)
|
|
|
|
{
|
|
|
|
if (!hl->root)
|
|
|
|
hl->root = ctx_node_new (hl, NULL,
|
|
|
|
moo_lang_get_default_context (hl->lang),
|
|
|
|
FALSE);
|
|
|
|
node = hl->root;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Line *prev = moo_line_buffer_get_line (hl->line_buf, lines->first - 1);
|
|
|
|
node = get_next_line_node (hl, prev);
|
|
|
|
}
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
g_return_val_if_fail (node != NULL, TRUE);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
hl->last_tag = NULL;
|
2005-10-13 07:08:18 -07:00
|
|
|
gtk_text_buffer_get_iter_at_line (hl->buffer, &iter, lines->first);
|
|
|
|
|
|
|
|
for (line_no = lines->first; line_no <= lines->last; ++line_no)
|
|
|
|
{
|
|
|
|
Line *line = moo_line_buffer_get_line (hl->line_buf, line_no);
|
|
|
|
MatchData match_data;
|
|
|
|
|
2006-02-26 22:37:34 -08:00
|
|
|
// g_assert (line->hl_info->tags || !line->hl_info->tags_applied || !line->hl_info->n_segments);
|
2005-10-13 07:08:18 -07:00
|
|
|
g_assert (line_no == gtk_text_iter_get_line (&iter));
|
|
|
|
|
|
|
|
line->hl_info->start_node = node;
|
2005-11-22 10:39:05 -08:00
|
|
|
line->hl_info->tags_applied = FALSE;
|
2005-10-13 07:08:18 -07:00
|
|
|
moo_line_erase_segments (line);
|
|
|
|
|
|
|
|
/* TODO: there is no need to recompute line if its start context matches
|
|
|
|
context implied by the previous line */
|
|
|
|
moo_match_data_init (&match_data, line_no, &iter, NULL);
|
2005-11-22 10:39:05 -08:00
|
|
|
node = hl_compute_line (hl, line, &match_data, node, apply_tags);
|
2005-10-13 07:08:18 -07:00
|
|
|
moo_match_data_destroy (&match_data);
|
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
g_print ("line %d, %d segments\n", line_no, line->hl_info->n_segments);
|
|
|
|
for (i = 0; i < line->hl_info->n_segments; ++i)
|
|
|
|
{
|
|
|
|
Segment *s = &line->hl_info->segments[i];
|
|
|
|
g_print ("segment %d: %d chars, context '%s'", i, s->len, s->ctx_node->ctx->name);
|
|
|
|
if (s->match_node)
|
|
|
|
g_print (", match context '%s'", s->match_node->ctx->name);
|
|
|
|
if (s->rule)
|
|
|
|
g_print (", rule '%s'", s->rule->debug_string);
|
|
|
|
g_print ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-10-13 07:08:18 -07:00
|
|
|
if (!gtk_text_iter_forward_line (&iter))
|
|
|
|
{
|
|
|
|
g_assert (line_no >= lines->last - 1); /* if last line is empty,
|
|
|
|
then this last line 'does not
|
|
|
|
really exist'*/
|
|
|
|
g_assert (line_no >= hl->line_buf->invalid.last - 1);
|
2005-11-20 23:48:11 -08:00
|
|
|
done = TRUE;
|
2005-11-22 10:41:12 -08:00
|
|
|
break;
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (line_no == hl->line_buf->invalid.last)
|
|
|
|
{
|
|
|
|
Line *next = moo_line_buffer_get_line (hl->line_buf, line_no + 1);
|
|
|
|
|
|
|
|
if (node == next->hl_info->start_node)
|
|
|
|
{
|
2005-11-20 23:48:11 -08:00
|
|
|
done = TRUE;
|
2005-11-22 10:41:12 -08:00
|
|
|
break;
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hl->line_buf->invalid.last++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timer && (g_timer_elapsed (timer, NULL) > secs))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-11-20 23:48:11 -08:00
|
|
|
if (!done)
|
|
|
|
{
|
|
|
|
hl->line_buf->invalid.first = line_no;
|
|
|
|
if (line_no <= lines->last)
|
|
|
|
hl->line_buf->invalid.first++;
|
|
|
|
moo_line_buffer_clamp_invalid (hl->line_buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BUF_SET_CLEAN (hl->line_buf);
|
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
if (timer)
|
|
|
|
g_timer_destroy (timer);
|
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
check_last_tag (hl);
|
2005-11-20 23:48:11 -08:00
|
|
|
_moo_text_buffer_highlighting_changed (MOO_TEXT_BUFFER (hl->buffer),
|
2005-11-22 10:39:05 -08:00
|
|
|
lines->first, line_no);
|
|
|
|
return done;
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
static gboolean
|
2005-10-13 07:08:18 -07:00
|
|
|
moo_highlighter_compute_timed (MooHighlighter *hl,
|
|
|
|
int first_line,
|
|
|
|
int last_line,
|
|
|
|
gboolean apply_tags,
|
|
|
|
int time)
|
|
|
|
{
|
|
|
|
Interval to_highlight;
|
|
|
|
|
|
|
|
if (!hl->lang || !hl->buffer)
|
2005-11-22 10:39:05 -08:00
|
|
|
return TRUE;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
if (BUF_CLEAN (hl->line_buf))
|
2005-11-22 10:39:05 -08:00
|
|
|
return TRUE;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
if (last_line < 0)
|
|
|
|
last_line = moo_text_btree_size (hl->line_buf->tree) - 1;
|
|
|
|
|
|
|
|
g_assert (first_line >= 0);
|
|
|
|
g_assert (last_line >= first_line);
|
|
|
|
|
|
|
|
to_highlight.first = first_line;
|
|
|
|
to_highlight.last = last_line;
|
|
|
|
|
|
|
|
if (hl->line_buf->invalid.first > to_highlight.last)
|
2005-11-22 10:39:05 -08:00
|
|
|
return TRUE;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
to_highlight.first = hl->line_buf->invalid.first;
|
2005-11-22 10:39:05 -08:00
|
|
|
return hl_compute_range (hl, &to_highlight, apply_tags, time);
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_highlighter_compute (MooHighlighter *hl,
|
|
|
|
int first,
|
|
|
|
int last,
|
|
|
|
gboolean apply_tags)
|
|
|
|
{
|
|
|
|
moo_highlighter_compute_timed (hl, first, last, apply_tags, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
compute_in_idle (MooHighlighter *hl)
|
|
|
|
{
|
|
|
|
hl->idle = 0;
|
|
|
|
|
|
|
|
if (!BUF_CLEAN (hl->line_buf))
|
|
|
|
moo_highlighter_compute_timed (hl, 0, -1, hl->apply_tags,
|
|
|
|
IDLE_HIGHLIGHT_TIME);
|
|
|
|
|
|
|
|
if (!BUF_CLEAN (hl->line_buf))
|
2005-11-22 10:39:05 -08:00
|
|
|
hl->idle = g_timeout_add_full (IDLE_HIGHLIGHT_PRIORITY,
|
|
|
|
IDLE_HIGHLIGHT_TIME,
|
|
|
|
(GSourceFunc) compute_in_idle,
|
|
|
|
hl, NULL);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_highlighter_queue_compute (MooHighlighter *hl,
|
|
|
|
gboolean apply_tags)
|
|
|
|
{
|
|
|
|
if (!hl->lang || !hl->buffer || BUF_CLEAN (hl->line_buf))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!hl->idle)
|
|
|
|
hl->idle = g_idle_add_full (IDLE_HIGHLIGHT_PRIORITY,
|
|
|
|
(GSourceFunc) compute_in_idle,
|
|
|
|
hl, NULL);
|
|
|
|
|
|
|
|
hl->apply_tags = apply_tags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
static gboolean
|
|
|
|
apply_in_idle (MooHighlighter *hl)
|
|
|
|
{
|
|
|
|
hl->apply_idle = 0;
|
|
|
|
hl->apply_to.empty = TRUE;
|
|
|
|
moo_highlighter_apply_tags (hl, hl->apply_to.first, hl->apply_to.last);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-13 07:08:18 -07:00
|
|
|
void
|
|
|
|
moo_highlighter_apply_tags (MooHighlighter *hl,
|
|
|
|
int first_line,
|
|
|
|
int last_line)
|
|
|
|
{
|
|
|
|
int line_no;
|
2005-11-22 10:39:05 -08:00
|
|
|
int total;
|
|
|
|
int first_changed, last_changed;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
if (!hl->lang || !hl->buffer)
|
|
|
|
return;
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
total = moo_text_btree_size (hl->line_buf->tree);
|
|
|
|
|
2005-10-13 07:08:18 -07:00
|
|
|
if (last_line < 0)
|
2005-11-22 10:39:05 -08:00
|
|
|
last_line = total - 1;
|
|
|
|
|
|
|
|
first_line = CLAMP (first_line, 0, total - 1);
|
|
|
|
last_line = CLAMP (last_line, first_line, total - 1);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
g_assert (first_line >= 0);
|
|
|
|
g_assert (last_line >= first_line);
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (!moo_highlighter_compute_timed (hl, first_line, last_line,
|
|
|
|
TRUE, COMPUTE_NOW_TIME))
|
|
|
|
{
|
|
|
|
if (!hl->apply_idle)
|
|
|
|
hl->apply_idle = g_idle_add ((GSourceFunc) apply_in_idle, hl);
|
|
|
|
|
|
|
|
hl->apply_to.empty = FALSE;
|
|
|
|
hl->apply_to.first = first_line;
|
|
|
|
hl->apply_to.last = last_line;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-11-22 10:41:12 -08:00
|
|
|
first_changed = last_changed = -1;
|
2005-11-22 20:56:30 -08:00
|
|
|
hl->last_tag = NULL;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
|
|
|
for (line_no = first_line; line_no <= last_line; ++line_no)
|
|
|
|
{
|
|
|
|
Line *line = moo_line_buffer_get_line (hl->line_buf, line_no);
|
|
|
|
HLInfo *info = line->hl_info;
|
|
|
|
guint i;
|
|
|
|
GtkTextIter t_start, t_end;
|
2005-11-22 10:39:05 -08:00
|
|
|
GSList *tags;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (line->hl_info->tags_applied)
|
2005-10-13 07:08:18 -07:00
|
|
|
continue;
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (first_changed < 0)
|
|
|
|
first_changed = line_no;
|
|
|
|
last_changed = line_no;
|
|
|
|
|
|
|
|
line->hl_info->tags_applied = TRUE;
|
2005-11-24 00:34:02 -08:00
|
|
|
tags = line->hl_info->tags;
|
|
|
|
line->hl_info->tags = NULL;
|
2005-11-22 10:39:05 -08:00
|
|
|
|
|
|
|
gtk_text_buffer_get_iter_at_line (hl->buffer, &t_start, line_no);
|
|
|
|
|
|
|
|
if (gtk_text_iter_ends_line (&t_start))
|
2005-11-24 00:34:02 -08:00
|
|
|
{
|
|
|
|
g_slist_foreach (tags, (GFunc) g_object_unref, NULL);
|
|
|
|
g_slist_free (tags);
|
2005-11-22 10:39:05 -08:00
|
|
|
continue;
|
2005-11-24 00:34:02 -08:00
|
|
|
}
|
2005-11-22 10:39:05 -08:00
|
|
|
|
|
|
|
t_end = t_start;
|
|
|
|
gtk_text_iter_forward_to_line_end (&t_end);
|
|
|
|
|
|
|
|
while (tags)
|
2005-10-13 07:08:18 -07:00
|
|
|
{
|
2005-11-22 10:39:05 -08:00
|
|
|
gtk_text_buffer_remove_tag (hl->buffer, tags->data, &t_start, &t_end);
|
2005-11-23 03:10:03 -08:00
|
|
|
g_object_unref (tags->data);
|
2005-11-22 10:39:05 -08:00
|
|
|
tags = g_slist_delete_link (tags, tags);
|
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
t_end = t_start;
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
for (i = 0; i < info->n_segments; ++i)
|
|
|
|
{
|
2005-10-13 07:08:18 -07:00
|
|
|
if (info->segments[i].len < 0)
|
|
|
|
gtk_text_iter_forward_to_line_end (&t_end);
|
|
|
|
else
|
|
|
|
gtk_text_iter_forward_chars (&t_end, info->segments[i].len);
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
apply_tag (hl, line, info->segments[i].ctx_node,
|
2005-10-13 07:08:18 -07:00
|
|
|
info->segments[i].match_node,
|
|
|
|
info->segments[i].rule,
|
2005-11-22 10:39:05 -08:00
|
|
|
&t_start, &t_end);
|
2005-10-13 07:08:18 -07:00
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
t_start = t_end;
|
|
|
|
}
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
2005-11-22 10:39:05 -08:00
|
|
|
|
2005-11-22 20:56:30 -08:00
|
|
|
check_last_tag (hl);
|
|
|
|
|
2005-11-22 10:39:05 -08:00
|
|
|
if (first_changed >= 0)
|
|
|
|
_moo_text_buffer_highlighting_changed (MOO_TEXT_BUFFER (hl->buffer),
|
|
|
|
first_changed, last_changed);
|
2005-10-13 07:08:18 -07:00
|
|
|
}
|
2005-10-16 22:23:40 -07:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
tag_set_scheme (G_GNUC_UNUSED gpointer whatever,
|
|
|
|
MooSyntaxTag *tag,
|
|
|
|
MooTextStyleScheme *scheme)
|
|
|
|
{
|
|
|
|
if (tag)
|
|
|
|
{
|
|
|
|
_moo_lang_erase_tag_style (GTK_TEXT_TAG (tag));
|
|
|
|
_moo_lang_set_tag_style (tag->rule ? tag->rule->context->lang : tag->ctx_node->ctx->lang,
|
|
|
|
GTK_TEXT_TAG (tag),
|
|
|
|
tag->rule ? tag->rule->context : tag->ctx_node->ctx,
|
|
|
|
tag->rule, scheme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ctx_node_set_scheme (CtxNode *node,
|
|
|
|
MooTextStyleScheme *scheme)
|
|
|
|
{
|
|
|
|
g_hash_table_foreach (node->match_tags, (GHFunc) tag_set_scheme, scheme);
|
|
|
|
tag_set_scheme (NULL, MOO_SYNTAX_TAG (node->context_tag), scheme);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
moo_highlighter_apply_scheme (MooHighlighter *hl,
|
|
|
|
MooTextStyleScheme *scheme)
|
|
|
|
{
|
|
|
|
g_return_if_fail (hl != NULL && scheme != NULL);
|
|
|
|
g_slist_foreach (hl->nodes, (GFunc) ctx_node_set_scheme, scheme);
|
|
|
|
}
|