medit/moo/mooedit/gtksourceview/gtksourcecontextengine.c

5398 lines
125 KiB
C
Raw Normal View History

2006-08-26 02:46:29 -07:00
/* -*- mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
* gtksourcecontextengine.c
*
* Copyright (C) 2003 - Gustavo Giráldez <gustavo.giraldez@gmx.net>
* Copyright (C) 2005, 2006 - Marco Barisione, Emanuele Aina
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* FIXME: toplevel children must have extend-parent=TRUE, because create_reg_all wants
end regex in toplevel context in this case */
#include "gtksourceview-i18n.h"
#include "gtksourcecontextengine.h"
#include "gtktextregion.h"
#include "gtksourcetag.h"
#include "gtksourcelanguage-private.h"
#include "gtksourcebuffer.h"
#include "eggregex.h"
#include <errno.h>
#include <string.h>
#undef ENABLE_DEBUG
#undef ENABLE_PROFILE
#undef ENABLE_CHECK_TREE
#ifdef ENABLE_DEBUG
#define DEBUG(x) (x)
#else
#define DEBUG(x)
#endif
#ifdef ENABLE_PROFILE
#define PROFILE(x) (x)
#else
#define PROFILE(x)
#endif
#if defined (ENABLE_DEBUG) || defined (ENABLE_PROFILE) || \
defined (ENABLE_CHECK_TREE)
#define NEED_DEBUG_ID
#endif
/* Regex used to match "\%{...@start}". */
#define START_REF_REGEX "(?<!\\\\)(\\\\\\\\)*\\\\%\\{(.*?)@start\\}"
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
#define FIRST_UPDATE_PRIORITY G_PRIORITY_HIGH_IDLE
#define INCREMENTAL_UPDATE_PRIORITY GTK_TEXT_VIEW_PRIORITY_VALIDATE
2006-08-26 02:46:29 -07:00
/* In milliseconds. */
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
#define FIRST_UPDATE_TIME_SLICE 10
#define INCREMENTAL_UPDATE_TIME_SLICE 30
2006-08-26 02:46:29 -07:00
#define GTK_SOURCE_CONTEXT_ENGINE_ERROR (gtk_source_context_engine_error_quark ())
/* Returns the definition corrsponding to the specified id. */
#define LOOKUP_DEFINITION(ce, id) \
(g_hash_table_lookup ((ce)->priv->definitions, (id)))
/* Can the context be terminated by ancestor? */
#define ANCESTOR_CAN_END_CONTEXT(context) \
(!(context)->definition->extend_parent || \
!(context)->all_ancestors_extend)
#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)
#define SEGMENT_IS_SIMPLE(s) CONTEXT_IS_SIMPLE ((s)->context)
#define SEGMENT_IS_CONTAINER(s) CONTEXT_IS_CONTAINER ((s)->context)
typedef struct _RegexInfo RegexInfo;
typedef struct _Regex Regex;
typedef struct _SubPatternDefinition SubPatternDefinition;
typedef struct _SubPattern SubPattern;
typedef struct _Segment Segment;
typedef struct _Context Context;
typedef struct _ContextPtr ContextPtr;
typedef struct _ContextDefinition ContextDefinition;
typedef struct _DefinitionChild DefinitionChild;
typedef struct _DefinitionsIter DefinitionsIter;
typedef struct _LineInfo LineInfo;
typedef struct _InvalidRegion InvalidRegion;
typedef enum {
GTK_SOURCE_CONTEXT_ENGINE_ERROR_DUPLICATED_ID = 0,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_ARGS,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_PARENT,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_REF,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_WHERE,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_START_REF,
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_REGEX,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_STYLE
2006-08-26 02:46:29 -07:00
} GtkSourceContextEngineError;
typedef enum {
CONTEXT_TYPE_SIMPLE = 0,
CONTEXT_TYPE_CONTAINER,
} ContextType;
typedef enum {
SUB_PATTERN_WHERE_DEFAULT = 0,
SUB_PATTERN_WHERE_START,
SUB_PATTERN_WHERE_END
} SubPatternWhere;
struct _RegexInfo
{
gchar *pattern;
EggRegexCompileFlags flags;
};
/* We do not use directly EggRegex to allow the use of "\%{...@start}". */
struct _Regex
{
union {
EggRegex *regex;
RegexInfo info;
} u;
guint ref_count;
guint resolved : 1;
};
struct _ContextDefinition
{
gchar *id;
ContextType type;
union
{
Regex *match;
struct {
Regex *start;
Regex *end;
} start_end;
} u;
/* Name of the style used for contexts of this type. */
gchar *style;
/* This is a list of DefinitionChild pointers. */
GSList *children;
/* Sub patterns (list of SubPatternDefinition pointers.) */
GSList *sub_patterns;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
guint n_sub_patterns;
2006-08-26 02:46:29 -07:00
/* Union of every regular expression we can find from this
* context. */
Regex *reg_all;
2006-08-26 17:04:13 -07:00
/* Should this context start only at the first line? */
guint first_line_only : 1;
2006-08-26 02:46:29 -07:00
/* Should this context end before end of the line (namely,
* before the line terminating characters)? */
guint end_at_line_end : 1;
/* Does this context can extend its parent? */
guint extend_parent : 1;
};
struct _SubPatternDefinition
{
#ifdef NEED_DEBUG_ID
/* We need the id only for debugging. */
gchar *id;
#endif
gchar *style;
SubPatternWhere where;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
/* index in the ContextDefinition's list */
guint index;
2006-08-26 02:46:29 -07:00
union
{
gint num;
gchar *name;
} u;
guint is_named : 1;
};
struct _DefinitionChild
{
ContextDefinition *definition;
/* Whether this child is a reference to all child contexts of
* <definition>. */
guint is_ref_all : 1;
};
struct _DefinitionsIter
{
GSList *children_stack;
};
struct _Context
{
/* Definition for the context. */
ContextDefinition *definition;
Context *parent;
ContextPtr *children;
/* This is the regex returned by regex_resolve() called on
* definition->start_end.end. */
Regex *end;
/* The regular expression containing every regular expression that
* could be matched in this context. */
Regex *reg_all;
GtkTextTag *tag;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
GtkTextTag **subpattern_tags;
2006-08-26 02:46:29 -07:00
guint ref_count;
guint frozen : 1;
/* Do all the ancestors extend their parent? */
guint all_ancestors_extend : 1;
};
struct _ContextPtr
{
ContextDefinition *definition;
ContextPtr *next;
union {
Context *context;
GHashTable *hash; /* char* -> Context* */
} u;
guint fixed : 1;
};
struct _Segment
{
Segment *parent;
Segment *next;
Segment *prev;
Segment *children;
Segment *last_child;
/* This is NULL if and only if it's a dummy segment which denotes
* inserted or deleted text. */
Context *context;
/* Subpatterns found in this segment. */
SubPattern *sub_patterns;
/* The context is used in the interval [start_at; end_at). */
gint start_at;
gint end_at;
};
struct _SubPattern
{
SubPatternDefinition *definition;
gint start_at;
gint end_at;
SubPattern *next;
};
/* Line terminator characters (\n, \r, \r\n, or unicode paragraph separator)
* are removed from the line text. The problem is that pcre does not understand
* arbitrary line terminators, so $ in pcre means (?=\n) (not quite, it's also
* end of matched string), while we really need "((?=\r\n)|(?=[\r\n])|(?=\xE2\x80\xA9)|$)".
* It could be worked around by replacing line terminator in matched text with
* \n, but it's a good source of errors, since offsets (not all, unfortunately) returned
* from pcre need to be compared to line length, and adjusted when necessary.
* Not using line terminator only means that \n can't be in patterns, it's not a
* big deal: line end can't be highlighted anyway; if a rule needs to match it, it can
* can use "$" as start and "^" as end (not in a single pattern, "$^" will never match).
*/
#define NEXT_LINE_OFFSET(l_) ((l_)->start_at + (l_)->length + (l_)->eol_length)
struct _LineInfo
{
/* Line text. */
gchar *text;
/* Character offset of the line in text buffer. */
gint start_at;
/* Character length of <text>. */
gint length;
/* Character length of line terminator, or 0 if it's the
* last line in buffer. */
gint eol_length;
};
struct _InvalidRegion
{
gboolean empty;
GtkTextMark *start;
GtkTextMark *end;
/* offset_at(end) - delta == original offset,
* i.e. offset in the tree */
gint delta;
};
struct _GtkSourceContextEnginePrivate
{
/* Language id. */
gchar *id;
GtkSourceLanguage *lang;
GtkTextBuffer *buffer;
GtkSourceStyleScheme *style_scheme;
/* Contains every ContextDefinition indexed by its id. */
GHashTable *definitions;
/* All tags indexed by style name: values are GSList's of tags, ref()'ed. */
GHashTable *tags;
/* Whether or not to actually highlight the buffer. */
gboolean highlight;
/* Region covering the unhighlighted text. */
GtkTextRegion *refresh_region;
/* Tree of contexts. */
Context *root_context;
Segment *root_segment;
Segment *hint;
/* list of Segment* */
GSList *invalid;
InvalidRegion invalid_region;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
guint first_update;
guint incremental_update;
2006-08-26 02:46:29 -07:00
/* Views highlight requests. */
GtkTextRegion *highlight_requests;
};
#ifdef ENABLE_CHECK_TREE
static void CHECK_TREE (GtkSourceContextEngine *ce);
static void CHECK_SEGMENT_LIST (Segment *segment);
static void CHECK_SEGMENT_CHILDREN (Segment *segment);
#else
#define CHECK_TREE(ce)
#define CHECK_SEGMENT_LIST(s)
#define CHECK_SEGMENT_CHILDREN(s)
#endif
static GQuark gtk_source_context_engine_error_quark (void) G_GNUC_CONST;
static Segment *create_segment (GtkSourceContextEngine *ce,
Segment *parent,
Context *context,
gint start_at,
gint end_at,
Segment *hint);
static Segment *segment_new (GtkSourceContextEngine *ce,
Segment *parent,
Context *context,
gint start_at,
gint end_at);
static Context *context_new (Context *parent,
ContextDefinition *definition,
const gchar *line_text);
static void context_unref (Context *context);
static void context_freeze (Context *context);
static void context_thaw (Context *context);
static void erase_segments (GtkSourceContextEngine *ce,
gint start,
gint end,
Segment *hint);
static void find_insertion_place (Segment *segment,
gint offset,
Segment **parent,
Segment **prev,
Segment **next,
Segment *hint);
static void segment_destroy (GtkSourceContextEngine *ce,
Segment *segment);
static void context_definition_free (ContextDefinition *definition);
static void segment_extend (Segment *state,
gint end_at);
static Context *ancestor_context_ends_here (Context *state,
LineInfo *line,
gint pos);
static void definition_iter_init (DefinitionsIter *iter,
ContextDefinition *definition);
static ContextDefinition *definition_iter_next (DefinitionsIter *iter);
static void definition_iter_destroy (DefinitionsIter *iter);
static void update_syntax (GtkSourceContextEngine *ce,
const GtkTextIter *end,
gint time);
static void install_idle_worker (GtkSourceContextEngine *ce);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
static void install_first_update (GtkSourceContextEngine *ce);
2006-08-26 02:46:29 -07:00
/* MODIFICATIONS AND STUFF ------------------------------------------------ */
static void
unhighlight_region_cb (G_GNUC_UNUSED gpointer style,
GSList *tags,
gpointer user_data)
{
struct {
GtkTextBuffer *buffer;
const GtkTextIter *start, *end;
} *data = user_data;
while (tags)
{
gtk_text_buffer_remove_tag (data->buffer,
tags->data,
data->start,
data->end);
tags = tags->next;
}
}
static void
unhighlight_region (GtkSourceContextEngine *ce,
const GtkTextIter *start,
const GtkTextIter *end)
{
struct {
GtkTextBuffer *buffer;
const GtkTextIter *start, *end;
} data = {ce->priv->buffer, start, end};
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (gtk_text_iter_equal (start, end))
return;
2006-08-26 02:46:29 -07:00
g_hash_table_foreach (ce->priv->tags, (GHFunc) unhighlight_region_cb, &data);
}
static void
set_tag_style (GtkSourceContextEngine *ce,
GtkTextTag *tag,
const gchar *style_name)
{
GtkSourceStyle *style;
g_return_if_fail (GTK_IS_TEXT_TAG (tag));
g_return_if_fail (style_name != NULL);
_gtk_source_style_unapply (tag);
if (!ce->priv->style_scheme)
return;
style = gtk_source_style_scheme_get_style (ce->priv->style_scheme, style_name);
if (!style)
{
const char *map_to = style_name;
while (!style && (map_to = g_hash_table_lookup (ce->priv->lang->priv->styles, map_to)))
style = gtk_source_style_scheme_get_style (ce->priv->style_scheme, map_to);
}
if (style)
{
_gtk_source_style_apply (style, tag);
gtk_source_style_free (style);
}
else
{
g_warning ("could not find style '%s'", style_name);
}
}
static GtkTextTag *
create_tag (GtkSourceContextEngine *ce,
const gchar *style_name)
{
GSList *tags;
GtkTextTag *new_tag;
GtkTextTagTable *table;
g_assert (style_name != NULL);
tags = g_hash_table_lookup (ce->priv->tags, style_name);
new_tag = g_object_new (GTK_TYPE_SOURCE_TAG, NULL);
table = gtk_text_buffer_get_tag_table (ce->priv->buffer);
gtk_text_tag_table_add (table, new_tag);
set_tag_style (ce, new_tag, style_name);
tags = g_slist_prepend (tags, new_tag);
g_hash_table_insert (ce->priv->tags, g_strdup (style_name), tags);
return new_tag;
}
/* Find tag which has to be overridden. */
static GtkTextTag *
get_parent_tag (Context *context,
const char *style)
{
while (context)
{
/* Lang files may repeat same style for nested contexts,
* ignore them. */
if (context->definition->style &&
strcmp (context->definition->style, style) != 0)
{
g_assert (context->tag != NULL);
return context->tag;
}
context = context->parent;
}
return NULL;
}
static GtkTextTag *
get_tag_for_parent (GtkSourceContextEngine *ce,
const char *style,
Context *parent)
{
GSList *tags;
GtkTextTag *parent_tag = NULL;
GtkTextTag *tag;
g_return_val_if_fail (style != NULL, NULL);
parent_tag = get_parent_tag (parent, style);
tags = g_hash_table_lookup (ce->priv->tags, style);
if (tags && (!parent_tag ||
gtk_text_tag_get_priority (tags->data) > gtk_text_tag_get_priority (parent_tag)))
{
GSList *link;
tag = tags->data;
/* Now get the tag with lowest priority, so that tag lists do not grow
* indefinitely. */
for (link = tags->next; link != NULL; link = link->next)
{
if (parent_tag &&
gtk_text_tag_get_priority (link->data) < gtk_text_tag_get_priority (parent_tag))
break;
tag = link->data;
}
}
else
{
tag = create_tag (ce, style);
#ifdef ENABLE_DEBUG
{
GString *style_path = g_string_new (style);
gint n;
while (parent)
{
if (parent->definition->style)
{
g_string_prepend (style_path, "/");
g_string_prepend (style_path,
parent->definition->style);
}
parent = parent->parent;
}
tags = g_hash_table_lookup (ce->priv->tags, style);
n = g_slist_length (tags);
g_print ("created %d tag for style %s: %s\n", n, style, style_path->str);
g_string_free (style_path, TRUE);
}
#endif
}
return tag;
}
static GtkTextTag *
get_subpattern_tag (GtkSourceContextEngine *ce,
Context *context,
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
SubPatternDefinition *sp_def)
2006-08-26 02:46:29 -07:00
{
if (!sp_def->style)
return NULL;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
g_assert (sp_def->index < context->definition->n_sub_patterns);
2006-08-26 02:46:29 -07:00
if (!context->subpattern_tags)
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
context->subpattern_tags = g_new0 (GtkTextTag*, context->definition->n_sub_patterns);
2006-08-26 02:46:29 -07:00
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (!context->subpattern_tags[sp_def->index])
context->subpattern_tags[sp_def->index] = get_tag_for_parent (ce, sp_def->style, context);
g_return_val_if_fail (context->subpattern_tags[sp_def->index] != NULL, NULL);
return context->subpattern_tags[sp_def->index];
2006-08-26 02:46:29 -07:00
}
static GtkTextTag *
get_context_tag (GtkSourceContextEngine *ce,
Context *context)
{
if (context->definition->style && !context->tag)
context->tag = get_tag_for_parent (ce,
context->definition->style,
context->parent);
return context->tag;
}
static void
apply_tags (GtkSourceContextEngine *ce,
Segment *segment,
gint start_offset,
gint end_offset)
{
GtkTextTag *tag;
GtkTextIter start_iter, end_iter;
SubPattern *sp;
guint i;
Segment *child;
g_assert (segment != NULL);
if (SEGMENT_IS_INVALID (segment))
return;
if (segment->start_at >= end_offset || segment->end_at <= start_offset)
return;
start_offset = MAX (start_offset, segment->start_at);
end_offset = MIN (end_offset, segment->end_at);
tag = get_context_tag (ce, segment->context);
if (tag)
{
gtk_text_buffer_get_iter_at_offset (ce->priv->buffer, &start_iter, start_offset);
gtk_text_buffer_get_iter_at_offset (ce->priv->buffer, &end_iter, end_offset);
gtk_text_buffer_apply_tag (ce->priv->buffer, tag, &start_iter, &end_iter);
}
for (sp = segment->sub_patterns, i = 0; sp != NULL; sp = sp->next, ++i)
{
if (sp->start_at >= start_offset && sp->end_at <= end_offset)
{
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
tag = get_subpattern_tag (ce, segment->context, sp->definition);
if (tag)
{
gtk_text_buffer_get_iter_at_offset (ce->priv->buffer, &start_iter,
MAX (start_offset, sp->start_at));
gtk_text_buffer_get_iter_at_offset (ce->priv->buffer, &end_iter,
MIN (end_offset, sp->end_at));
gtk_text_buffer_apply_tag (ce->priv->buffer, tag, &start_iter, &end_iter);
}
2006-08-26 02:46:29 -07:00
}
}
for (child = segment->children;
child != NULL && child->start_at < end_offset;
child = child->next)
{
if (child->end_at <= start_offset)
continue;
apply_tags (ce, child, start_offset, end_offset);
}
}
/**
* highlight_region:
*
* @ce: a #GtkSourceContextEngine.
* @start: the beginning of the region to highlight.
* @end: the end of the region to highlight.
*
* Highlights the specified region.
*/
static void
highlight_region (GtkSourceContextEngine *ce,
GtkTextIter *start,
GtkTextIter *end)
{
#ifdef ENABLE_PROFILE
GTimer *timer;
#endif
if (gtk_text_iter_starts_line (end))
gtk_text_iter_backward_char (end);
if (gtk_text_iter_compare (start, end) >= 0)
return;
#ifdef ENABLE_PROFILE
timer = g_timer_new ();
#endif
/* First we need to delete tags in the regions. */
unhighlight_region (ce, start, end);
apply_tags (ce, ce->priv->root_segment,
gtk_text_iter_get_offset (start),
gtk_text_iter_get_offset (end));
#ifdef ENABLE_PROFILE
g_print ("highlight (from %d to %d), %g ms elapsed\n",
gtk_text_iter_get_offset (start),
gtk_text_iter_get_offset (end),
g_timer_elapsed (timer, NULL) * 1000);
g_timer_destroy (timer);
#endif
}
/**
* ensure_highlighted:
*
* @ce: a #GtkSourceContextEngine.
* @start: the beginning of the region to highlight.
* @end: the end of the region to highlight.
*
* Updates text tags in reanalyzed parts of given area.
* It applies tags according to whatever is in the syntax
* tree currently, so highlighting may not be correct
* (gtk_source_context_engine_update_highlight is the method
* that actually ensures correct highlighting).
*/
static void
ensure_highlighted (GtkSourceContextEngine *ce,
const GtkTextIter *start,
const GtkTextIter *end)
{
GtkTextRegion *region;
GtkTextRegionIterator reg_iter;
/* Get the subregions not yet highlighted. */
region = gtk_text_region_intersect (ce->priv->refresh_region, start, end);
if (!region)
return;
gtk_text_region_get_iterator (region, &reg_iter, 0);
/* Highlight all subregions from the intersection.
* hopefully this will only be one subregion. */
while (!gtk_text_region_iterator_is_end (&reg_iter))
{
GtkTextIter s, e;
gtk_text_region_iterator_get_subregion (&reg_iter, &s, &e);
highlight_region (ce, &s, &e);
gtk_text_region_iterator_next (&reg_iter);
}
gtk_text_region_destroy (region, TRUE);
/* Remove the just highlighted region. */
gtk_text_region_subtract (ce->priv->refresh_region, start, end);
}
/**
* refresh_range:
*
* @ce: a #GtkSourceContextEngine.
* @start: the beginning of updated area.
* @end: the end of updated area.
* @modify_refresh_region: whether updated area should be added to
* refresh_region.
*
* Marks the area as updated - notifies view about it, and adds it to
* refresh_region if %modify_refresh_region is TRUE (update_syntax may
* process huge area though actually updated is couple of lines, so in
* that case update_syntax() takes care of refresh_region, and this
* function only notifies the view).
*/
static void
refresh_range (GtkSourceContextEngine *ce,
const GtkTextIter *start,
const GtkTextIter *end,
gboolean modify_refresh_region)
{
GtkTextIter real_end;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (gtk_text_iter_equal (start, end))
return;
2006-08-26 02:46:29 -07:00
if (modify_refresh_region)
gtk_text_region_add (ce->priv->refresh_region, start, end);
/* Here we need to make sure we do not make it redraw next line */
real_end = *end;
if (gtk_text_iter_starts_line (&real_end))
/* XXX if it's in the middle of \r\n, what line is it? */
gtk_text_iter_backward_char (&real_end);
g_signal_emit_by_name (ce->priv->buffer,
"highlight_updated",
start,
&real_end);
}
static gint
segment_cmp (Segment *s1,
Segment *s2)
{
if (s1->start_at < s2->start_at)
return -1;
else if (s1->start_at > s2->start_at)
return 1;
/* one of them must be zero-length */
g_assert (s1->start_at == s1->end_at || s2->start_at == s2->end_at);
#ifdef ENABLE_DEBUG
/* A new zero-length segment should never be created if there is
* already an invalid segment. */
g_assert_not_reached ();
#endif
g_return_val_if_reached (s1->end_at < s2->end_at ? -1 :
(s1->end_at > s2->end_at ? 1 : 0));
}
static void
add_invalid (GtkSourceContextEngine *ce,
Segment *segment)
{
#ifdef ENABLE_CHECK_TREE
g_assert (!g_slist_find (ce->priv->invalid, segment));
#endif
g_assert (SEGMENT_IS_INVALID (segment));
ce->priv->invalid = g_slist_insert_sorted (ce->priv->invalid,
segment,
(GCompareFunc) segment_cmp);
DEBUG (g_print ("%d invalid\n", g_slist_length (ce->priv->invalid)));
}
static void
remove_invalid (GtkSourceContextEngine *ce,
Segment *segment)
{
g_assert (g_slist_find (ce->priv->invalid, segment) != NULL);
ce->priv->invalid = g_slist_remove (ce->priv->invalid, segment);
}
static void
fix_offsets_insert_ (Segment *segment,
gint start,
gint delta)
{
Segment *child;
SubPattern *sp;
g_assert (segment->start_at >= start);
if (!delta)
return;
segment->start_at += delta;
segment->end_at += delta;
for (child = segment->children; child != NULL; child = child->next)
fix_offsets_insert_ (child, start, delta);
for (sp = segment->sub_patterns; sp != NULL; sp = sp->next)
{
sp->start_at += delta;
sp->end_at += delta;
}
}
static void
find_insertion_place_forward_ (Segment *segment,
gint offset,
Segment *start,
Segment **parent,
Segment **prev,
Segment **next)
{
Segment *child;
g_assert (start->end_at < offset);
for (child = start; child != NULL; child = child->next)
{
if (child->start_at <= offset && child->end_at >= offset)
return find_insertion_place (child, offset, parent, prev, next, NULL);
if (child->end_at == offset)
{
if (SEGMENT_IS_INVALID (child))
{
*parent = child;
*prev = NULL;
*next = NULL;
}
else
{
*prev = child;
*next = child->next;
*parent = segment;
}
return;
}
if (child->end_at < offset)
{
*prev = child;
continue;
}
if (child->start_at > offset)
{
*next = child;
break;
}
g_assert_not_reached ();
}
*parent = segment;
}
static void
find_insertion_place_backward_ (Segment *segment,
gint offset,
Segment *start,
Segment **parent,
Segment **prev,
Segment **next)
{
Segment *child;
g_assert (start->end_at >= offset);
for (child = start; child != NULL; child = child->prev)
{
if (child->start_at <= offset && child->end_at >= offset)
return find_insertion_place (child, offset, parent, prev, next, NULL);
if (child->end_at == offset)
{
if (SEGMENT_IS_INVALID (child))
{
*parent = child;
*prev = NULL;
*next = NULL;
}
else
{
*prev = child;
*next = child->next;
*parent = segment;
}
return;
}
if (child->end_at < offset)
{
*prev = child;
*next = child->next;
break;
}
if (child->start_at > offset)
{
*next = child;
continue;
}
g_assert_not_reached ();
}
*parent = segment;
}
static void
find_insertion_place (Segment *segment,
gint offset,
Segment **parent,
Segment **prev,
Segment **next,
Segment *hint)
{
g_assert (segment->start_at <= offset && segment->end_at >= offset);
*prev = NULL;
*next = NULL;
if (SEGMENT_IS_INVALID (segment) || segment->children == NULL)
{
*parent = segment;
return;
}
/* XXX grand child might be invalid, so we still can get two
* adjacent zero-length segments, and crash */
if (segment->start_at == offset)
{
if (SEGMENT_IS_INVALID (segment->children) &&
segment->children->start_at == offset)
{
*parent = segment->children;
}
else
{
*parent = segment;
*next = segment->children;
}
return;
}
if (hint)
while (hint && hint->parent != segment)
hint = hint->parent;
if (!hint)
hint = segment->children;
if (hint->end_at < offset)
find_insertion_place_forward_ (segment, offset, hint, parent, prev, next);
else
find_insertion_place_backward_ (segment, offset, hint, parent, prev, next);
}
static Segment *
get_invalid_at_ (GtkSourceContextEngine *ce,
gint offset)
{
GSList *link = ce->priv->invalid;
while (link)
{
Segment *segment = link->data;
link = link->next;
if (segment->start_at > offset)
break;
if (segment->end_at < offset)
continue;
return segment;
}
return NULL;
}
static void
segment_add_subpattern (Segment *state,
SubPattern *sp)
{
sp->next = state->sub_patterns;
state->sub_patterns = sp;
}
static SubPattern *
sub_pattern_new (Segment *segment,
gint start_at,
gint end_at,
SubPatternDefinition *sp_def)
{
SubPattern *sp;
sp = g_new0 (SubPattern, 1);
sp->start_at = start_at;
sp->end_at = end_at;
sp->definition = sp_def;
segment_add_subpattern (segment, sp);
return sp;
}
static inline void
sub_pattern_free (SubPattern *sp)
{
g_free (sp);
}
static void
segment_make_invalid_ (GtkSourceContextEngine *ce,
Segment *segment)
{
Context *ctx;
SubPattern *sp;
g_assert (!SEGMENT_IS_INVALID (segment));
sp = segment->sub_patterns;
segment->sub_patterns = NULL;
while (sp)
{
SubPattern *next = sp->next;
sub_pattern_free (sp);
sp = next;
}
ctx = segment->context;
segment->context = NULL;
add_invalid (ce, segment);
context_unref (ctx);
}
static Segment *
simple_segment_split_ (GtkSourceContextEngine *ce,
Segment *segment,
gint offset)
{
SubPattern *subpatterns, *sp;
Segment *new_segment, *invalid;
gint end_at = segment->end_at;
g_assert (SEGMENT_IS_SIMPLE (segment));
g_assert (segment->start_at < offset && offset < segment->end_at);
subpatterns = segment->sub_patterns;
segment->sub_patterns = NULL;
segment->end_at = offset;
invalid = create_segment (ce, segment->parent, NULL, offset, offset, segment);
new_segment = create_segment (ce, segment->parent, segment->context, offset, end_at, invalid);
sp = subpatterns;
while (sp != NULL)
{
Segment *append_to = NULL;
SubPattern *next = sp->next;
if (sp->end_at <= offset)
{
append_to = segment;
}
else if (sp->start_at >= offset)
{
append_to = new_segment;
}
else
{
sub_pattern_new (new_segment,
offset,
sp->end_at,
sp->definition);
sp->end_at = offset;
append_to = segment;
}
segment_add_subpattern (append_to, sp);
sp = next;
}
return invalid;
}
2006-08-26 17:04:13 -07:00
/**
* invalidate_region:
*
* @ce: a #GtkSourceContextEngine.
* @offset: the start of invalidated area.
* @length: the length of the area.
*
* Adds the area to the invalid region and queues highlighting.
* %length may be negative which means deletion; positive
* means insertion; 0 means "something happened here", it's
* treated as zero-length insertion.
*/
2006-08-26 02:46:29 -07:00
static gboolean
invalidate_region (GtkSourceContextEngine *ce,
gint offset,
gint length)
{
InvalidRegion *region = &ce->priv->invalid_region;
GtkTextBuffer *buffer = ce->priv->buffer;
GtkTextIter iter;
gint end_offset;
end_offset = length >= 0 ? offset + length : offset;
if (region->empty)
{
region->empty = FALSE;
region->delta = length;
gtk_text_buffer_get_iter_at_offset (buffer, &iter, offset);
gtk_text_buffer_move_mark (buffer, region->start, &iter);
gtk_text_iter_set_offset (&iter, end_offset);
gtk_text_buffer_move_mark (buffer, region->end, &iter);
}
else
{
gtk_text_buffer_get_iter_at_mark (buffer, &iter, region->start);
if (gtk_text_iter_get_offset (&iter) > offset)
{
gtk_text_iter_set_offset (&iter, offset);
gtk_text_buffer_move_mark (buffer, region->start, &iter);
}
gtk_text_buffer_get_iter_at_mark (buffer, &iter, region->end);
if (gtk_text_iter_get_offset (&iter) < end_offset)
{
gtk_text_iter_set_offset (&iter, end_offset);
gtk_text_buffer_move_mark (buffer, region->end, &iter);
}
region->delta += length;
}
DEBUG (({
gint start, end;
gtk_text_buffer_get_iter_at_mark (buffer, &iter, region->start);
start = gtk_text_iter_get_offset (&iter);
gtk_text_buffer_get_iter_at_mark (buffer, &iter, region->end);
end = gtk_text_iter_get_offset (&iter);
g_assert (start <= end - region->delta);
}));
CHECK_TREE (ce);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
install_first_update (ce);
2006-08-26 02:46:29 -07:00
return TRUE;
}
2006-08-26 17:04:13 -07:00
/**
* insert_range:
*
* @ce: a #GtkSourceContextEngine.
* @offset: the start of new segment.
* @length: the length of the segment.
*
* Updates segment tree after insertion: it updates tree
* offsets as appropriate, and inserts a new invalid segment
* or extends existing invalid segment as %offset, so
* after the call segment [offset, offset + length) is marked
* invalid in the tree.
* It may be safely called with length == 0 at any moment
* (and it's used here and there).
*/
2006-08-26 02:46:29 -07:00
static void
insert_range (GtkSourceContextEngine *ce,
gint offset,
gint length)
{
Segment *parent, *prev = NULL, *next = NULL, *new_segment;
Segment *segment;
/* If there is an invalid segment adjacent to offset, use it.
* Otherwise, find the deepest segment to split and insert
* dummy segment in there. */
if (!(parent = get_invalid_at_ (ce, offset)))
find_insertion_place (ce->priv->root_segment, offset,
&parent, &prev, &next,
ce->priv->hint);
g_assert (parent->start_at <= offset);
g_assert (parent->end_at >= offset);
g_assert (!prev || prev->parent == parent);
g_assert (!next || next->parent == parent);
g_assert (!prev || prev->next == next);
g_assert (!next || next->prev == prev);
if (SEGMENT_IS_INVALID (parent))
{
/* If length is zero, and we already have an invalid segment there,
* do nothing. */
if (!length)
return;
segment = parent;
}
else if (SEGMENT_IS_SIMPLE (parent))
{
/* If it's a simple context, then:
* if one of its ends is offset, then we just invalidate it;
* otherwise, we split it into two, and insert zero-lentgh
* invalid segment in the middle. */
if (parent->start_at < offset && parent->end_at > offset)
{
segment = simple_segment_split_ (ce, parent, offset);
}
else
{
segment_make_invalid_ (ce, parent);
segment = parent;
}
}
else
{
/* Just insert new zero-length invalid segment. */
new_segment = segment_new (ce, parent, NULL, offset, offset);
new_segment->next = next;
new_segment->prev = prev;
if (next)
next->prev = new_segment;
else
parent->last_child = new_segment;
if (prev)
prev->next = new_segment;
else
parent->children = new_segment;
segment = new_segment;
}
g_assert (!segment->children);
if (length != 0)
{
/* now fix offsets in all the segments "to the right"
* of segment. */
while (segment)
{
Segment *tmp;
SubPattern *sp;
for (tmp = segment->next; tmp != NULL; tmp = tmp->next)
fix_offsets_insert_ (tmp, offset, length);
segment->end_at += length;
for (sp = segment->sub_patterns; sp != NULL; sp = sp->next)
{
if (sp->start_at > offset)
sp->start_at += length;
if (sp->end_at > offset)
sp->end_at += length;
}
segment = segment->parent;
}
}
CHECK_TREE (ce);
}
2006-08-26 17:04:13 -07:00
/**
* gtk_source_context_engine_text_inserted:
*
* @ce: a #GtkSourceContextEngine.
* @start_offset: the start of inserted text.
* @end_offset: the end of inserted text.
*
* Called from GtkTextBuffer::insert_text.
*/
2006-08-26 02:46:29 -07:00
static void
gtk_source_context_engine_text_inserted (GtkSourceEngine *engine,
gint start_offset,
gint end_offset)
{
g_return_if_fail (start_offset < end_offset);
invalidate_region (GTK_SOURCE_CONTEXT_ENGINE (engine),
start_offset,
end_offset - start_offset);
}
static inline gint
fix_offset_delete_ (gint offset,
gint start,
gint length)
{
if (offset > start)
{
if (offset >= start + length)
offset -= length;
else
offset = start;
}
return offset;
}
static void
fix_offsets_delete_ (Segment *segment,
gint offset,
gint length,
Segment *hint)
{
Segment *child;
SubPattern *sp;
g_return_if_fail (segment->end_at > offset);
if (hint)
while (hint && hint->parent != segment)
hint = hint->parent;
if (!hint)
hint = segment->children;
for (child = hint; child != NULL; child = child->next)
{
if (child->end_at <= offset)
continue;
fix_offsets_delete_ (child, offset, length, NULL);
}
for (child = hint ? hint->prev : NULL; child != NULL; child = child->prev)
{
if (child->end_at <= offset)
break;
fix_offsets_delete_ (child, offset, length, NULL);
}
for (sp = segment->sub_patterns; sp != NULL; sp = sp->next)
{
sp->start_at = fix_offset_delete_ (sp->start_at, offset, length);
sp->end_at = fix_offset_delete_ (sp->end_at, offset, length);
}
segment->start_at = fix_offset_delete_ (segment->start_at, offset, length);
segment->end_at = fix_offset_delete_ (segment->end_at, offset, length);
}
2006-08-26 17:04:13 -07:00
/**
* delete_range_:
*
* @ce: a #GtkSourceContextEngine.
* @start: the start of deleted area.
* @end: the end of deleted area.
*
* Updates segment tree after deletion: removes segments at deleted
* interval, updates tree offsets, etc.
* It's called only from update_tree().
*/
2006-08-26 02:46:29 -07:00
static void
delete_range_ (GtkSourceContextEngine *ce,
gint start,
gint end)
{
g_return_if_fail (start < end);
/* XXX it may make two invalid segments adjacent, and we can get crash */
erase_segments (ce, start, end, NULL);
fix_offsets_delete_ (ce->priv->root_segment, start, end - start, ce->priv->hint);
/* no need to invalidate at start, update_tree will do it */
CHECK_TREE (ce);
};
2006-08-26 17:04:13 -07:00
/**
* gtk_source_context_engine_text_deleted:
*
* @ce: a #GtkSourceContextEngine.
* @offset: the start of deleted text.
* @length: the length (in characters) of deleted text.
*
* Called from GtkTextBuffer::delete_range.
*/
2006-08-26 02:46:29 -07:00
static void
gtk_source_context_engine_text_deleted (GtkSourceEngine *engine,
gint offset,
gint length)
{
g_return_if_fail (length > 0);
invalidate_region (GTK_SOURCE_CONTEXT_ENGINE (engine),
offset,
- length);
}
/**
* get_invalid_segment:
*
* @ce: a #GtkSourceContextEngine.
*
* Returns first invalid segment, or NULL.
*/
static Segment *
get_invalid_segment (GtkSourceContextEngine *ce)
{
g_return_val_if_fail (ce->priv->invalid_region.empty, NULL);
return ce->priv->invalid ? ce->priv->invalid->data : NULL;
}
/**
* get_invalid_line:
*
* @ce: a #GtkSourceContextEngine.
*
* Returns first invalid line, or -1.
*/
static gint
get_invalid_line (GtkSourceContextEngine *ce)
{
GtkTextIter iter;
gint offset = G_MAXINT;
if (!ce->priv->invalid_region.empty)
{
gint tmp;
gtk_text_buffer_get_iter_at_mark (ce->priv->buffer,
&iter,
ce->priv->invalid_region.start);
tmp = gtk_text_iter_get_offset (&iter);
offset = MIN (offset, tmp);
}
if (ce->priv->invalid)
{
Segment *segment = ce->priv->invalid->data;
offset = MIN (offset, segment->start_at);
}
if (offset == G_MAXINT)
return -1;
gtk_text_buffer_get_iter_at_offset (ce->priv->buffer, &iter, offset);
return gtk_text_iter_get_line (&iter);
}
/**
* update_tree:
*
* @ce: a #GtkSourceContextEngine.
*
* Modifies syntax tree according to data in invalid_region.
*/
static void
update_tree (GtkSourceContextEngine *ce)
{
InvalidRegion *region = &ce->priv->invalid_region;
gint start, end, delta;
gint erase_start, erase_end;
GtkTextIter iter;
if (region->empty)
return;
gtk_text_buffer_get_iter_at_mark (ce->priv->buffer, &iter, region->start);
start = gtk_text_iter_get_offset (&iter);
gtk_text_buffer_get_iter_at_mark (ce->priv->buffer, &iter, region->end);
end = gtk_text_iter_get_offset (&iter);
delta = region->delta;
g_assert (start <= MIN (end, end - delta));
/* Here start and end are actual offsets in the buffer (they do not match offsets
* in the tree if delta is not zero); delta is how much was inserted/removed.
* First, we insert/delete range from the tree, to make offsets in tree
* match offsets in the buffer. Then, create an invalid segment for the rest
* of the area if needed. */
if (delta > 0)
insert_range (ce, start, delta);
else if (delta < 0)
delete_range_ (ce, end, end - delta);
if (delta <= 0)
{
erase_start = start;
erase_end = end;
}
else
{
erase_start = start + delta;
erase_end = end;
}
if (erase_start < erase_end)
{
erase_segments (ce, erase_start, erase_end, NULL);
create_segment (ce, ce->priv->root_segment, NULL, erase_start, erase_end, NULL);
}
else if (!get_invalid_at_ (ce, start))
{
insert_range (ce, start, 0);
}
region->empty = TRUE;
#ifdef ENABLE_CHECK_TREE
g_assert (get_invalid_at_ (ce, start) != NULL);
CHECK_TREE (ce);
#endif
}
/* XXX make sure regions requested and highlighted are the same,
so we don't install an idle just because a view gave us a
start iter of the line it doesn't care about (and vice versa
in update_syntax) */
static void
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
gtk_source_context_engine_update_highlight (GtkSourceEngine *engine,
const GtkTextIter *start,
const GtkTextIter *end,
gboolean synchronous)
2006-08-26 02:46:29 -07:00
{
gint invalid_line;
gint end_line;
GtkSourceContextEngine *ce = GTK_SOURCE_CONTEXT_ENGINE (engine);
if (!ce->priv->highlight)
return;
invalid_line = get_invalid_line (ce);
end_line = gtk_text_iter_get_line (end);
if (gtk_text_iter_starts_line (end) && end_line > 0)
end_line -= 1;
if (invalid_line < 0 || invalid_line > end_line)
{
ensure_highlighted (ce, start, end);
}
else if (synchronous)
{
/* analyze whole region */
update_syntax (ce, end, 0);
ensure_highlighted (ce, start, end);
}
else
{
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (gtk_text_iter_get_line (start) >= invalid_line)
{
gtk_text_region_add (ce->priv->highlight_requests, start, end);
}
else
{
GtkTextIter valid_end = *start;
gtk_text_iter_set_line (&valid_end, invalid_line);
ensure_highlighted (ce, start, &valid_end);
gtk_text_region_add (ce->priv->highlight_requests, &valid_end, end);
}
install_first_update (ce);
2006-08-26 02:46:29 -07:00
}
}
static void
enable_highlight (GtkSourceContextEngine *ce,
gboolean enable)
{
GtkTextIter start, end;
if (!enable == !ce->priv->highlight)
return;
ce->priv->highlight = enable != 0;
gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (ce->priv->buffer),
&start, &end);
if (enable)
refresh_range (ce, &start, &end, TRUE);
else
unhighlight_region (ce, &start, &end);
}
static void
buffer_notify_highlight_cb (GtkSourceContextEngine *ce)
{
gboolean highlight;
g_object_get (ce->priv->buffer, "highlight", &highlight, NULL);
enable_highlight (ce, highlight);
}
/* IDLE WORKER CODE ------------------------------------------------------- */
static gboolean
all_analyzed (GtkSourceContextEngine *ce)
{
return ce->priv->invalid == NULL && ce->priv->invalid_region.empty;
}
/**
* idle_worker:
*
* @ce: #GtkSourceContextEngine.
*
* Analyzes a batch in idle. Stops when
* whole buffer is analyzed.
*/
static gboolean
idle_worker (GtkSourceContextEngine *ce)
{
g_return_val_if_fail (ce->priv->buffer != NULL, FALSE);
/* analyze batch of text */
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
update_syntax (ce, NULL, INCREMENTAL_UPDATE_TIME_SLICE);
2006-08-26 02:46:29 -07:00
CHECK_TREE (ce);
if (all_analyzed (ce))
{
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
ce->priv->incremental_update = 0;
2006-08-26 02:46:29 -07:00
return FALSE;
}
return TRUE;
}
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
static gboolean
first_update_callback (GtkSourceContextEngine *ce)
{
g_return_val_if_fail (ce->priv->buffer != NULL, FALSE);
/* analyze batch of text */
update_syntax (ce, NULL, FIRST_UPDATE_TIME_SLICE);
CHECK_TREE (ce);
ce->priv->first_update = 0;
if (!all_analyzed (ce))
install_idle_worker (ce);
return FALSE;
}
2006-08-26 02:46:29 -07:00
/**
* install_idle_worker:
*
* @ce: #GtkSourceContextEngine.
*
* Schedules reanalyzing buffer in idle.
* Always safe to call.
*/
static void
install_idle_worker (GtkSourceContextEngine *ce)
{
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (!ce->priv->first_update && !ce->priv->incremental_update)
ce->priv->incremental_update =
g_idle_add_full (INCREMENTAL_UPDATE_PRIORITY,
2006-08-26 02:46:29 -07:00
(GSourceFunc) idle_worker, ce, NULL);
}
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
static void
install_first_update (GtkSourceContextEngine *ce)
{
if (!ce->priv->first_update)
{
if (ce->priv->incremental_update)
{
g_source_remove (ce->priv->incremental_update);
ce->priv->incremental_update = 0;
}
ce->priv->first_update =
g_idle_add_full (FIRST_UPDATE_PRIORITY,
(GSourceFunc) first_update_callback,
ce, NULL);
}
}
2006-08-26 02:46:29 -07:00
/* GtkSourceContextEngine class ------------------------------------------- */
G_DEFINE_TYPE (GtkSourceContextEngine, _gtk_source_context_engine, GTK_TYPE_SOURCE_ENGINE)
static GQuark
gtk_source_context_engine_error_quark (void)
{
static GQuark err_q = 0;
if (err_q == 0)
err_q = g_quark_from_static_string ("gtk-source-context-engine-error-quark");
return err_q;
}
static void
remove_tags_hash_cb (G_GNUC_UNUSED gpointer style,
GSList *tags,
GtkTextTagTable *table)
{
GSList *l = tags;
while (l != NULL)
{
gtk_text_tag_table_remove (table, l->data);
g_object_unref (l->data);
l = l->next;
}
g_slist_free (tags);
}
static void
destroy_tags_hash (GtkSourceContextEngine *ce)
{
g_hash_table_foreach (ce->priv->tags, (GHFunc) remove_tags_hash_cb,
gtk_text_buffer_get_tag_table (ce->priv->buffer));
g_hash_table_destroy (ce->priv->tags);
ce->priv->tags = NULL;
}
/**
* gtk_source_context_engine_attach_buffer:
*
* @ce: #GtkSourceContextEngine.
* @buffer: buffer.
*
* Detaches engine from previous buffer, and attaches to @buffer if
* it's not NULL.
*/
static void
gtk_source_context_engine_attach_buffer (GtkSourceEngine *engine,
GtkTextBuffer *buffer)
{
GtkSourceContextEngine *ce = GTK_SOURCE_CONTEXT_ENGINE (engine);
g_return_if_fail (!buffer || GTK_IS_TEXT_BUFFER (buffer));
if (ce->priv->buffer == buffer)
return;
/* Detach previous buffer if there is one. */
if (ce->priv->buffer)
{
g_signal_handlers_disconnect_by_func (ce->priv->buffer,
(gpointer) buffer_notify_highlight_cb,
ce);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (ce->priv->first_update)
g_source_remove (ce->priv->first_update);
if (ce->priv->incremental_update)
g_source_remove (ce->priv->incremental_update);
ce->priv->first_update = 0;
ce->priv->incremental_update = 0;
2006-08-26 02:46:29 -07:00
segment_destroy (ce, ce->priv->root_segment);
context_unref (ce->priv->root_context);
g_slist_free (ce->priv->invalid);
ce->priv->root_segment = NULL;
ce->priv->root_context = NULL;
ce->priv->invalid = NULL;
gtk_text_buffer_delete_mark (ce->priv->buffer,
ce->priv->invalid_region.start);
gtk_text_buffer_delete_mark (ce->priv->buffer,
ce->priv->invalid_region.end);
ce->priv->invalid_region.start = NULL;
ce->priv->invalid_region.end = NULL;
/* this deletes tags from the tag table, therefore there is no need
* in removing tags from the text (it may be very slow). */
destroy_tags_hash (ce);
if (ce->priv->refresh_region)
gtk_text_region_destroy (ce->priv->refresh_region, FALSE);
if (ce->priv->highlight_requests)
gtk_text_region_destroy (ce->priv->highlight_requests, FALSE);
ce->priv->refresh_region = NULL;
ce->priv->highlight_requests = NULL;
}
ce->priv->buffer = buffer;
if (buffer)
{
gchar *root_id;
ContextDefinition *main_definition;
GtkTextIter start, end;
/* Create the root context. */
root_id = g_strdup_printf ("%s:%s", ce->priv->id, ce->priv->id);
main_definition = g_hash_table_lookup (ce->priv->definitions,
root_id);
g_free (root_id);
if (!main_definition)
{
g_warning (_ ("Missing main language "
"definition (id = \"%s\".)"),
ce->priv->id);
return;
}
ce->priv->root_context = context_new (NULL, main_definition, NULL);
ce->priv->root_segment = create_segment (ce, NULL, ce->priv->root_context, 0, 0, NULL);
ce->priv->tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
gtk_text_buffer_get_bounds (buffer, &start, &end);
ce->priv->invalid_region.start = gtk_text_buffer_create_mark (buffer, NULL,
&start, TRUE);
ce->priv->invalid_region.end = gtk_text_buffer_create_mark (buffer, NULL,
&end, FALSE);
ce->priv->invalid_region.empty = FALSE;
ce->priv->invalid_region.delta = gtk_text_buffer_get_char_count (buffer);
g_object_get (ce->priv->buffer, "highlight", &ce->priv->highlight, NULL);
ce->priv->refresh_region = gtk_text_region_new (buffer);
ce->priv->highlight_requests = gtk_text_region_new (buffer);
g_signal_connect_swapped (buffer, "notify::highlight",
G_CALLBACK (buffer_notify_highlight_cb), ce);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
install_first_update (ce);
2006-08-26 02:46:29 -07:00
}
}
static void
set_tag_style_hash_cb (const char *style,
GSList *tags,
GtkSourceContextEngine *ce)
{
while (tags)
{
set_tag_style (ce, tags->data, style);
tags = tags->next;
}
}
static void
gtk_source_context_engine_set_style_scheme (GtkSourceEngine *engine,
GtkSourceStyleScheme *scheme)
{
GtkSourceContextEngine *ce;
g_return_if_fail (GTK_IS_SOURCE_CONTEXT_ENGINE (engine));
g_return_if_fail (GTK_IS_SOURCE_STYLE_SCHEME (scheme));
ce = GTK_SOURCE_CONTEXT_ENGINE (engine);
if (scheme == ce->priv->style_scheme)
return;
if (ce->priv->style_scheme)
g_object_unref (ce->priv->style_scheme);
ce->priv->style_scheme = g_object_ref (scheme);
g_hash_table_foreach (ce->priv->tags, (GHFunc) set_tag_style_hash_cb, ce);
}
static void
gtk_source_context_engine_finalize (GObject *object)
{
GtkSourceContextEngine *ce = GTK_SOURCE_CONTEXT_ENGINE (object);
if (ce->priv->buffer != NULL)
{
g_critical ("finalizing engine with attached buffer");
/* Disconnect the buffer (if there is one), which destroys almost
* everything. */
gtk_source_context_engine_attach_buffer (GTK_SOURCE_ENGINE (ce), NULL);
}
g_assert (!ce->priv->tags);
g_assert (!ce->priv->root_context);
g_assert (!ce->priv->root_segment);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
g_assert (!ce->priv->first_update);
g_assert (!ce->priv->incremental_update);
2006-08-26 02:46:29 -07:00
g_hash_table_destroy (ce->priv->definitions);
g_free (ce->priv->id);
if (ce->priv->style_scheme)
g_object_unref (ce->priv->style_scheme);
G_OBJECT_CLASS (_gtk_source_context_engine_parent_class)->finalize (object);
}
static void
_gtk_source_context_engine_class_init (GtkSourceContextEngineClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkSourceEngineClass *engine_class = GTK_SOURCE_ENGINE_CLASS (klass);
object_class->finalize = gtk_source_context_engine_finalize;
engine_class->attach_buffer = gtk_source_context_engine_attach_buffer;
engine_class->text_inserted = gtk_source_context_engine_text_inserted;
engine_class->text_deleted = gtk_source_context_engine_text_deleted;
engine_class->update_highlight = gtk_source_context_engine_update_highlight;
engine_class->set_style_scheme = gtk_source_context_engine_set_style_scheme;
g_type_class_add_private (object_class, sizeof (GtkSourceContextEnginePrivate));
}
static void
_gtk_source_context_engine_init (GtkSourceContextEngine *ce)
{
ce->priv = G_TYPE_INSTANCE_GET_PRIVATE (ce, GTK_TYPE_SOURCE_CONTEXT_ENGINE,
GtkSourceContextEnginePrivate);
ce->priv->definitions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) context_definition_free);
}
GtkSourceContextEngine *
_gtk_source_context_engine_new (GtkSourceLanguage *lang)
{
GtkSourceContextEngine *ce;
g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (lang), NULL);
ce = g_object_new (GTK_TYPE_SOURCE_CONTEXT_ENGINE, NULL);
ce->priv->id = g_strdup (lang->priv->id);
ce->priv->lang = lang;
return ce;
}
/* REGEX HANDLING --------------------------------------------------------- */
static Regex *
regex_ref (Regex *regex)
{
if (regex)
regex->ref_count++;
return regex;
}
static void
regex_unref (Regex *regex)
{
if (regex && --regex->ref_count == 0)
{
if (regex->resolved)
egg_regex_unref (regex->u.regex);
else
g_free (regex->u.info.pattern);
g_free (regex);
}
}
static gboolean
find_single_byte_escape (const gchar *string)
{
const char *p = string;
while ((p = strstr (p, "\\C")))
{
const char *slash;
gboolean found;
if (p == string)
return TRUE;
found = TRUE;
slash = p - 1;
while (slash >= string && *slash == '\\')
{
found = !found;
slash--;
}
if (found)
return TRUE;
p += 2;
}
return FALSE;
}
/**
* regex_new:
*
* @pattern: the regular expression.
* @flags: compile options for @pattern.
* @error: location to store the error occuring, or NULL to ignore errors.
*
* Creates a new regex.
*
* Return value: a newly-allocated #Regex.
*/
static Regex *
regex_new (const gchar *pattern,
EggRegexCompileFlags flags,
GError **error)
{
Regex *regex;
if (find_single_byte_escape (pattern))
{
g_set_error (error, GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_REGEX,
"using \\C is not supported");
return NULL;
}
regex = g_new0 (Regex, 1);
regex->ref_count = 1;
if (egg_regex_match_simple (START_REF_REGEX, pattern, 0, 0))
{
regex->resolved = FALSE;
regex->u.info.pattern = g_strdup (pattern);
regex->u.info.flags = flags;
}
else
{
regex->resolved = TRUE;
regex->u.regex = egg_regex_new (pattern, flags, 0, error);
if (!regex->u.regex)
{
g_free (regex);
regex = NULL;
}
else
{
egg_regex_optimize (regex->u.regex, NULL);
}
}
return regex;
}
static gint
sub_pattern_to_int (const gchar *name)
{
guint64 number;
gchar *end_name;
if (!*name)
return -1;
errno = 0;
number = g_ascii_strtoull (name, &end_name, 10);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
g_return_val_if_fail (!errno && number < G_MAXINT && !*end_name, -1);
2006-08-26 02:46:29 -07:00
return number;
}
static gboolean
replace_start_regex (const EggRegex *regex,
const gchar *matched_text,
GString *expanded_regex,
gpointer user_data)
{
gchar *num_string, *subst, *subst_escaped, *escapes;
gint num;
struct
{
Regex *start_regex;
const gchar *matched_text;
} *data = user_data;
escapes = egg_regex_fetch (regex, 1, matched_text);
num_string = egg_regex_fetch (regex, 2, matched_text);
num = sub_pattern_to_int (num_string);
if (num < 0)
subst = egg_regex_fetch_named (data->start_regex->u.regex,
data->matched_text,
num_string);
else
subst = egg_regex_fetch (data->start_regex->u.regex,
num,
data->matched_text);
if (subst)
{
subst_escaped = egg_regex_escape_string (subst, -1);
}
else
{
g_warning ("Invalid group: %s", num_string);
subst_escaped = g_strdup ("");
}
g_string_append (expanded_regex, escapes);
g_string_append (expanded_regex, subst_escaped);
g_free (escapes);
g_free (num_string);
g_free (subst);
g_free (subst_escaped);
return FALSE;
}
/**
* regex_resolve:
*
* @regex: a #Regex.
* @start_regex: a #Regex.
* @matched_text: the text matched against @start_regex.
*
* If the regular expression does not contain references to the start
* regular expression, the functions increases the reference count
* of @regex and returns it.
*
* If the regular expression contains references to the start regular
* expression in the form "\%{start_sub_pattern@start}", it replaces
* them (they are extracted from @start_regex and @matched_text) and
* returns the new regular expression.
*
* Return value: a #Regex.
*/
static Regex *
regex_resolve (Regex *regex,
Regex *start_regex,
const gchar *matched_text)
{
EggRegex *start_ref;
gchar *expanded_regex;
Regex *new_regex;
struct {
Regex *start_regex;
const gchar *matched_text;
} data;
if (!regex || regex->resolved)
return regex_ref (regex);
start_ref = egg_regex_new (START_REF_REGEX, 0, 0, NULL);
data.start_regex = start_regex;
data.matched_text = matched_text;
expanded_regex = egg_regex_replace_eval (start_ref,
regex->u.info.pattern,
-1, 0, 0,
replace_start_regex,
&data);
new_regex = regex_new (expanded_regex, regex->u.info.flags, NULL);
if (!new_regex || !new_regex->resolved)
{
regex_unref (new_regex);
g_warning ("Regular expression %s cannot be expanded.",
regex->u.info.pattern);
/* Returns a regex that nevers matches. */
new_regex = regex_new ("$never-match^", 0, NULL);
}
egg_regex_unref (start_ref);
return new_regex;
}
static gboolean
regex_match (Regex *regex,
const gchar *line,
gint line_length,
gint line_pos)
{
gint byte_length = line_length;
gint byte_pos = line_pos;
g_assert (regex->resolved);
if (line_length > 0)
byte_length = (g_utf8_offset_to_pointer (line, line_length) - line);
if (line_pos > 0)
byte_pos = (g_utf8_offset_to_pointer (line, line_pos) - line);
return egg_regex_match_full (regex->u.regex, line,
byte_length, byte_pos,
0, NULL);
}
static gchar *
regex_fetch (Regex *regex,
const gchar *line,
gint num)
{
g_assert (regex->resolved);
return egg_regex_fetch (regex->u.regex, num, line);
}
static void
regex_fetch_pos (Regex *regex,
const gchar *text,
gint num,
gint *start_pos,
gint *end_pos)
{
gint byte_start_pos, byte_end_pos;
g_assert (regex->resolved);
if (!egg_regex_fetch_pos (regex->u.regex, num, &byte_start_pos, &byte_end_pos))
{
if (start_pos)
*start_pos = -1;
if (end_pos)
*end_pos = -1;
}
else
{
if (start_pos)
*start_pos = g_utf8_pointer_to_offset (text, text + byte_start_pos);
if (end_pos)
*end_pos = g_utf8_pointer_to_offset (text, text + byte_end_pos);
}
}
static void
regex_fetch_named_pos (Regex *regex,
const gchar *text,
const gchar *name,
gint *start_pos,
gint *end_pos)
{
gint byte_start_pos, byte_end_pos;
g_assert (regex->resolved);
if (!egg_regex_fetch_named_pos (regex->u.regex, name, &byte_start_pos, &byte_end_pos))
{
if (start_pos)
*start_pos = -1;
if (end_pos)
*end_pos = -1;
}
else
{
if (start_pos)
*start_pos = g_utf8_pointer_to_offset (text, text + byte_start_pos);
if (end_pos)
*end_pos = g_utf8_pointer_to_offset (text, text + byte_end_pos);
}
}
static const gchar *
regex_get_pattern (Regex *regex)
{
g_return_val_if_fail (regex && regex->resolved, "");
return egg_regex_get_pattern (regex->u.regex);
}
/* SYNTAX TREE ------------------------------------------------------------ */
/**
* apply_sub_patterns:
*
* @contextstate: a #Context.
* @line_starts_at: beginning offset of the line.
* @line: the line to analyze.
* @line_pos: the position inside @line.
* @line_length: the length of @line.
* @regex: regex that matched.
* @where: kind of sub patterns to apply.
*
* Applies sub patterns of kind @where to the matched text.
*/
static void
apply_sub_patterns (Segment *state,
LineInfo *line,
Regex *regex,
SubPatternWhere where)
{
GSList *sub_pattern_list = state->context->definition->sub_patterns;
while (sub_pattern_list != NULL)
{
SubPatternDefinition *sp_def = sub_pattern_list->data;
if (sp_def->where == where)
{
gint start_pos;
gint end_pos;
if (sp_def->is_named)
regex_fetch_named_pos (regex,
line->text,
sp_def->u.name,
&start_pos,
&end_pos);
else
regex_fetch_pos (regex,
line->text,
sp_def->u.num,
&start_pos,
&end_pos);
if (start_pos >= 0 && start_pos != end_pos)
{
sub_pattern_new (state,
line->start_at + start_pos,
line->start_at + end_pos,
sp_def);
}
}
sub_pattern_list = sub_pattern_list->next;
}
}
/**
* apply_match:
*
* @state: the current state of the parser.
* @line_starts_at: beginning offset of the line.
* @line: the line to analyze.
* @line_pos: the position inside @line.
* @line_length: the length of @line.
* @regex: regex that matched.
* @where: kind of sub patterns to apply.
*
* Moves @line_pos after the matched text. @line_pos is not
* updated and the function returns %FALSE if the match cannot be
* applied beacuse an ancestor ends in the middle of the matched
* text.
*
* If the match can be applied the function applies the appropriate
* sub patterns.
*
* Return value: %TRUE if the match can be applied.
*/
static gboolean
can_apply_match (Context *state,
LineInfo *line,
gint match_start,
gint *match_end,
Regex *regex)
{
gint end_match_pos;
gboolean ancestor_ends;
gint pos;
ancestor_ends = FALSE;
/* end_match_pos is the position of the end of the matched regex. */
regex_fetch_pos (regex, line->text, 0, NULL, &end_match_pos);
/* Verify if an ancestor ends in the matched text. */
if (ANCESTOR_CAN_END_CONTEXT (state))
{
pos = match_start + 1;
while (pos < end_match_pos)
{
if (ancestor_context_ends_here (state, line, pos))
{
ancestor_ends = TRUE;
break;
}
pos++;
}
}
else
{
pos = end_match_pos;
}
if (ancestor_ends)
{
/* An ancestor ends in the middle of the match, we verify
* if the regex matches against the available string before
* the end of the ancestor.
* For instance in C a net-address context matches even if
* it contains the end of a multi-line comment. */
/* XXX pos and match_start ?? */
if (!regex_match (regex, line->text, pos, match_start))
{
/* This match is not valid, so we can try to match
* the next definition, so the position should not
* change. */
return FALSE;
}
}
*match_end = pos;
return TRUE;
}
static gboolean
apply_match (Segment *state,
LineInfo *line,
gint *line_pos,
Regex *regex,
SubPatternWhere where)
{
gint match_end;
if (!can_apply_match (state->context, line, *line_pos, &match_end, regex))
return FALSE;
segment_extend (state, line->start_at + match_end);
apply_sub_patterns (state, line, regex, where);
*line_pos = match_end;
return TRUE;
}
static Regex *
create_reg_all (Context *context,
ContextDefinition *definition)
{
DefinitionsIter iter;
ContextDefinition *child_def;
GString *all;
Regex *regex;
g_return_val_if_fail ((!context && definition) || (context && !definition), NULL);
if (!definition)
definition = context->definition;
all = g_string_new ("(");
/* Closing regex. */
if (definition->type == CONTEXT_TYPE_CONTAINER &&
definition->u.start_end.end != NULL)
{
Regex *end;
if (definition->u.start_end.end->resolved)
{
end = definition->u.start_end.end;
}
else
{
g_return_val_if_fail (context && context->end, NULL);
end = context->end;
}
g_string_append (all, regex_get_pattern (end));
g_string_append (all, "|");
}
/* Ancestors. */
if (context)
{
Context *tmp = context;
while (ANCESTOR_CAN_END_CONTEXT (tmp))
{
if (!tmp->definition->extend_parent)
{
g_string_append (all, regex_get_pattern (tmp->parent->end));
g_string_append (all, "|");
}
tmp = tmp->parent;
}
}
/* Children. */
definition_iter_init (&iter, definition);
while ((child_def = definition_iter_next (&iter)))
{
Regex *child_regex = NULL;
switch (child_def->type)
{
case CONTEXT_TYPE_CONTAINER:
child_regex = child_def->u.start_end.start;
break;
case CONTEXT_TYPE_SIMPLE:
child_regex = child_def->u.match;
break;
default:
g_return_val_if_reached (NULL);
}
if (child_regex)
{
g_string_append (all, regex_get_pattern (child_regex));
g_string_append (all, "|");
}
}
definition_iter_destroy (&iter);
if (all->len > 1)
g_string_truncate (all, all->len - 1);
g_string_append (all, ")");
if (!(regex = regex_new (all->str, 0, NULL)))
{
/* regex_new could fail, for instance if there are different
* named sub-patterns with the same name. */
g_warning ("Cannot create a regex for all the transitions, "
"the syntax highlighting process will be slower "
"than usual.");
}
g_string_free (all, TRUE);
return regex;
}
static Context *
context_ref (Context *context)
{
if (context)
context->ref_count++;
return context;
}
static Context *
context_new (Context *parent,
ContextDefinition *definition,
const gchar *line_text)
{
Context *context;
context = g_new0 (Context, 1);
context->ref_count = 1;
context->definition = definition;
context->parent = parent;
if (!parent || (parent->all_ancestors_extend &&
parent->definition->extend_parent))
{
context->all_ancestors_extend = TRUE;
}
if (line_text &&
definition->type == CONTEXT_TYPE_CONTAINER &&
definition->u.start_end.end)
{
context->end = regex_resolve (definition->u.start_end.end,
definition->u.start_end.start,
line_text);
}
/* Create reg_all. If it is possibile we share the same reg_all
* for more contexts storing it in the definition. */
if (ANCESTOR_CAN_END_CONTEXT (context) ||
(definition->type == CONTEXT_TYPE_CONTAINER &&
definition->u.start_end.end &&
!definition->u.start_end.end->resolved))
{
context->reg_all = create_reg_all (context, NULL);
}
else
{
if (!definition->reg_all)
definition->reg_all = create_reg_all (NULL, definition);
context->reg_all = regex_ref (definition->reg_all);
}
#ifdef ENABLE_DEBUG
{
GString *str = g_string_new (definition->id);
Context *tmp = context->parent;
while (tmp)
{
g_string_prepend (str, "/");
g_string_prepend (str, tmp->definition->id);
tmp = tmp->parent;
}
g_print ("created context %s: %s\n", definition->id, str->str);
g_string_free (str, TRUE);
}
#endif
return context;
}
static void
context_unref_hash_cb (G_GNUC_UNUSED gpointer text,
Context *context)
{
context->parent = NULL;
context_unref (context);
}
static gboolean
remove_context_cb (G_GNUC_UNUSED gpointer text,
Context *context,
Context *target)
{
return context == target;
}
static void
context_remove_child (Context *parent,
Context *context)
{
ContextPtr *ptr, *prev = NULL;
gboolean delete = TRUE;
g_assert (context->parent == parent);
for (ptr = context->parent->children; ptr; ptr = ptr->next)
{
if (ptr->definition == context->definition)
break;
prev = ptr;
}
g_assert (ptr != NULL);
if (!ptr->fixed)
{
g_hash_table_foreach_remove (ptr->u.hash,
(GHRFunc) remove_context_cb,
context);
if (g_hash_table_size (ptr->u.hash))
delete = FALSE;
}
if (delete)
{
if (prev)
prev->next = ptr->next;
else
context->parent->children = ptr->next;
if (!ptr->fixed)
g_hash_table_destroy (ptr->u.hash);
g_free (ptr);
}
}
/**
* context_unref:
*
* @context: the context.
*
* Decreases reference count and removes @context
* from the tree when it drops to zero.
*/
static void
context_unref (Context *context)
{
ContextPtr *children;
if (!context || --context->ref_count)
return;
DEBUG (g_print ("destroying context %s\n", context->definition->id));
children = context->children;
context->children = NULL;
while (children)
{
ContextPtr *ptr = children;
children = children->next;
if (ptr->fixed)
{
ptr->u.context->parent = NULL;
context_unref (ptr->u.context);
}
else
{
g_hash_table_foreach (ptr->u.hash,
(GHFunc) context_unref_hash_cb,
NULL);
g_hash_table_destroy (ptr->u.hash);
}
g_free (ptr);
}
if (context->parent)
context_remove_child (context->parent, context);
regex_unref (context->end);
regex_unref (context->reg_all);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
g_free (context->subpattern_tags);
2006-08-26 02:46:29 -07:00
g_free (context);
}
static void
context_freeze_hash_cb (G_GNUC_UNUSED gpointer text,
Context *context)
{
context_freeze (context);
}
static void
context_freeze (Context *ctx)
{
ContextPtr *ptr;
g_assert (!ctx->frozen);
ctx->frozen = TRUE;
context_ref (ctx);
for (ptr = ctx->children; ptr != NULL; ptr = ptr->next)
{
if (ptr->fixed)
{
context_freeze (ptr->u.context);
}
else
{
g_hash_table_foreach (ptr->u.hash,
(GHFunc) context_freeze_hash_cb,
NULL);
}
}
}
static void
get_child_contexts_hash_cb (G_GNUC_UNUSED gpointer text,
Context *context,
GSList **list)
{
*list = g_slist_prepend (*list, context);
}
static void
context_thaw (Context *ctx)
{
ContextPtr *ptr;
if (!ctx->frozen)
return;
for (ptr = ctx->children; ptr != NULL; )
{
ContextPtr *next = ptr->next;
if (ptr->fixed)
{
context_thaw (ptr->u.context);
}
else
{
GSList *children = NULL;
g_hash_table_foreach (ptr->u.hash,
(GHFunc) get_child_contexts_hash_cb,
&children);
g_slist_foreach (children, (GFunc) context_thaw, NULL);
g_slist_free (children);
}
ptr = next;
}
ctx->frozen = FALSE;
context_unref (ctx);
}
static Context *
create_child_context (Context *parent,
ContextDefinition *definition,
const gchar *line_text)
{
Context *context;
ContextPtr *ptr;
gchar *match = NULL;
g_return_val_if_fail (parent != NULL, NULL);
for (ptr = parent->children;
ptr != NULL && ptr->definition != definition;
ptr = ptr->next) ;
if (!ptr)
{
ptr = g_new0 (ContextPtr, 1);
ptr->next = parent->children;
parent->children = ptr;
ptr->definition = definition;
if (definition->type != CONTEXT_TYPE_CONTAINER ||
!definition->u.start_end.end ||
definition->u.start_end.end->resolved)
{
ptr->fixed = TRUE;
}
if (!ptr->fixed)
ptr->u.hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
if (ptr->fixed)
{
context = ptr->u.context;
}
else
{
match = regex_fetch (definition->u.start_end.start, line_text, 0);
g_return_val_if_fail (match != NULL, NULL);
context = g_hash_table_lookup (ptr->u.hash, match);
}
if (context)
{
g_free (match);
return context_ref (context);
}
context = context_new (parent, definition, line_text);
g_return_val_if_fail (context != NULL, NULL);
if (ptr->fixed)
ptr->u.context = context;
else
g_hash_table_insert (ptr->u.hash, match, context);
return context;
};
static Segment *
segment_new (GtkSourceContextEngine *ce,
Segment *parent,
Context *context,
gint start_at,
gint end_at)
{
Segment *segment;
segment = g_new0 (Segment, 1);
segment->parent = parent;
segment->context = context_ref (context);
segment->start_at = start_at;
segment->end_at = end_at;
if (!context)
add_invalid (ce, segment);
return segment;
}
static void
find_segment_position_forward_ (Segment *segment,
gint start_at,
gint end_at,
Segment **prev,
Segment **next)
{
g_assert (segment->start_at <= start_at);
while (segment)
{
if (segment->end_at == start_at)
{
while (segment->next && segment->next->start_at == start_at)
segment = segment->next;
*prev = segment;
*next = segment->next;
break;
}
if (segment->start_at == end_at)
{
*next = segment;
*prev = segment->prev;
break;
}
if (segment->start_at > end_at)
{
*next = segment;
break;
}
if (segment->end_at < start_at)
*prev = segment;
segment = segment->next;
}
}
static void
find_segment_position_backward_ (Segment *segment,
gint start_at,
gint end_at,
Segment **prev,
Segment **next)
{
g_assert (start_at < segment->end_at);
while (segment)
{
if (segment->end_at <= start_at)
{
*prev = segment;
break;
}
g_assert (segment->start_at >= end_at);
*next = segment;
segment = segment->prev;
}
}
static void
find_segment_position (Segment *parent,
Segment *hint,
gint start_at,
gint end_at,
Segment **prev,
Segment **next)
{
Segment *tmp;
g_assert (parent->start_at <= start_at && end_at <= parent->end_at);
g_assert (!hint || hint->parent == parent);
*prev = *next = NULL;
if (!parent->children)
return;
if (!parent->children->next)
{
tmp = parent->children;
if (start_at >= tmp->end_at)
*prev = tmp;
else
*next = tmp;
return;
}
if (!hint)
hint = parent->children;
if (hint->end_at <= start_at)
return find_segment_position_forward_ (hint, start_at, end_at, prev, next);
else
return find_segment_position_backward_ (hint, start_at, end_at, prev, next);
}
static Segment *
create_segment (GtkSourceContextEngine *ce,
Segment *parent,
Context *context,
gint start_at,
gint end_at,
Segment *hint)
{
Segment *segment;
g_assert (!parent || (parent->start_at <= start_at && end_at <= parent->end_at));
segment = segment_new (ce, parent, context, start_at, end_at);
if (parent)
{
Segment *prev, *next;
if (!hint)
{
hint = ce->priv->hint;
while (hint && hint->parent != parent)
hint = hint->parent;
}
find_segment_position (parent, hint,
start_at, end_at,
&prev, &next);
g_assert ((!parent->children && !prev && !next) ||
(parent->children && (prev || next)));
g_assert (!prev || prev->next == next);
g_assert (!next || next->prev == prev);
segment->next = next;
segment->prev = prev;
if (next)
next->prev = segment;
else
parent->last_child = segment;
if (prev)
prev->next = segment;
else
parent->children = segment;
CHECK_SEGMENT_LIST (parent);
}
return segment;
}
static void
segment_extend (Segment *state,
gint end_at)
{
while (state && state->end_at < end_at)
{
state->end_at = end_at;
state = state->parent;
}
CHECK_SEGMENT_LIST (state->parent);
}
static void
segment_destroy_children (GtkSourceContextEngine *ce,
Segment *segment)
{
Segment *children;
SubPattern *sp;
g_assert (segment != NULL);
children = segment->children;
segment->children = NULL;
segment->last_child = NULL;
while (children)
{
Segment *tmp = children;
children = children->next;
segment_destroy (ce, tmp);
}
for (sp = segment->sub_patterns; sp; sp = sp->next)
sub_pattern_free (sp);
segment->sub_patterns = NULL;
}
static void
segment_destroy (GtkSourceContextEngine *ce,
Segment *segment)
{
g_assert (segment != NULL);
segment_destroy_children (ce, segment);
/* segment neighbours and parent may be invalid here,
* so we only can unset the hint */
if (ce->priv->hint == segment)
ce->priv->hint = NULL;
if (SEGMENT_IS_INVALID (segment))
remove_invalid (ce, segment);
context_unref (segment->context);
#ifdef ENABLE_DEBUG
g_assert (!g_slist_find (ce->priv->invalid, segment));
memset (segment, 0, sizeof (Segment));
#else
g_free (segment);
#endif
}
static gboolean
container_context_starts_here (GtkSourceContextEngine *ce,
Segment *state,
ContextDefinition *definition,
LineInfo *line,
gint *line_pos,
Segment **new_state,
Segment **hint)
{
Context *new_context;
Segment *new_segment;
gint match_end;
/* We can have a container context definition (i.e. the main
* language definition) without start_end.start. */
if (definition->u.start_end.start == NULL)
return FALSE;
if (!regex_match (definition->u.start_end.start,
line->text, line->length,
*line_pos))
{
return FALSE;
}
new_context = create_child_context (state->context, definition, line->text);
g_return_val_if_fail (new_context != NULL, FALSE);
if (!can_apply_match (new_context, line, *line_pos, &match_end,
definition->u.start_end.start))
{
context_unref (new_context);
return FALSE;
}
segment_extend (state, line->start_at + match_end);
new_segment = create_segment (ce, state, new_context,
line->start_at + *line_pos,
line->start_at + match_end,
*hint);
apply_sub_patterns (new_segment, line,
definition->u.start_end.start,
SUB_PATTERN_WHERE_START);
*line_pos = match_end;
*new_state = new_segment;
*hint = NULL;
context_unref (new_context);
return TRUE;
}
static gboolean
simple_context_starts_here (GtkSourceContextEngine *ce,
Segment *state,
ContextDefinition *definition,
LineInfo *line,
gint *line_pos,
Segment **new_state,
Segment **hint)
{
gint match_end;
Context *new_context;
Segment *new_segment;
g_return_val_if_fail (definition->u.match != NULL, FALSE);
if (!regex_match (definition->u.match, line->text, line->length, *line_pos))
return FALSE;
new_context = create_child_context (state->context, definition, line->text);
g_return_val_if_fail (new_context != NULL, FALSE);
if (!can_apply_match (new_context, line, *line_pos, &match_end, definition->u.match))
{
context_unref (new_context);
return FALSE;
}
segment_extend (state, line->start_at + match_end);
new_segment = create_segment (ce, state, new_context,
line->start_at + *line_pos,
line->start_at + match_end,
*hint);
apply_sub_patterns (new_segment, line, definition->u.match, SUB_PATTERN_WHERE_DEFAULT);
*line_pos = match_end;
*new_state = state;
*hint = new_segment;
context_unref (new_context);
return TRUE;
}
/**
* child_starts_here:
*
* @state: the current state.
* @curr_definition: child #ContextDefinition.
* @line: the line to analyze.
* @line_pos: the position inside @line.
* @line_length: the length of @line.
* @new_state: where to store the new state.
*
* Verifies if a context of the type in @curr_definition starts at
* @line_pos in @line. If the contexts start here @new_state and
* @line_pos are updated.
*
* Return value: %TRUE if the context starts here.
*/
static gboolean
child_starts_here (GtkSourceContextEngine *ce,
Segment *state,
ContextDefinition *definition,
LineInfo *line,
gint *line_pos,
Segment **new_state,
Segment **hint)
{
switch (definition->type)
{
case CONTEXT_TYPE_SIMPLE:
return simple_context_starts_here (ce,
state,
definition,
line,
line_pos,
new_state,
hint);
case CONTEXT_TYPE_CONTAINER:
return container_context_starts_here (ce,
state,
definition,
line,
line_pos,
new_state,
hint);
default:
g_return_val_if_reached (FALSE);
}
}
static gboolean
segment_ends_here (Segment *state,
LineInfo *line,
gint pos)
{
g_assert (SEGMENT_IS_CONTAINER (state));
return state->context->definition->u.start_end.end &&
regex_match (state->context->end,
line->text,
line->length,
pos);
}
/**
* ancestor_ends_here:
*
* @state: current state.
* @line: the line to analyze.
* @line_pos: the position inside @line.
* @line_length: the length of @line.
* @new_state: where to store the new state.
*
* Verifies if an ancestor context ends at the current position. If
* state changed and @new_state is not NULL, then the new state is stored
* in @new_state, and descendants of @new_state are closed, so the
* terminating segment becomes current state.
*
* Return value: %TRUE if an ancestor ends at the given position.
*/
static Context *
ancestor_context_ends_here (Context *state,
LineInfo *line,
gint line_pos)
{
Context *current_context;
GSList *current_context_list;
GSList *check_ancestors;
Context *terminating_context;
/* A context can be terminated by the parent if extend_parent is
* FALSE, so we need to verify the end of all the parents of
* not-extending contexts. The list is ordered by ascending
* depth. */
check_ancestors = NULL;
current_context = state;
while (ANCESTOR_CAN_END_CONTEXT (current_context))
{
if (!current_context->definition->extend_parent)
check_ancestors = g_slist_prepend (check_ancestors,
current_context->parent);
current_context = current_context->parent;
}
/* The first context that ends here terminates its descendants. */
terminating_context = NULL;
current_context_list = check_ancestors;
while (current_context_list)
{
current_context = current_context_list->data;
if (current_context->end &&
current_context->end->u.regex &&
regex_match (current_context->end,
line->text,
line->length,
line_pos))
{
terminating_context = current_context;
break;
}
current_context_list = current_context_list->next;
}
g_slist_free (check_ancestors);
return terminating_context;
}
static gboolean
ancestor_ends_here (Segment *state,
LineInfo *line,
gint line_pos,
Segment **new_state)
{
Context *terminating_context;
terminating_context = ancestor_context_ends_here (state->context, line, line_pos);
if (new_state && terminating_context)
{
/* We have found a context that ends here, so we close
* all the descendants. terminating_segment will be
* closed by next next_segment() call from analyze_line. */
Segment *current_segment = state;
while (current_segment->context != terminating_context)
{
g_assert (current_segment->end_at >= line->start_at + line_pos);
current_segment = current_segment->parent;
}
*new_state = current_segment;
g_assert (*new_state != NULL);
}
return terminating_context != NULL;
}
/**
* next_segment:
*
* @ce: #GtkSourceContextEngine.
* @state: current state.
* @line: analyzed line.
* @line_pos: position inside @line.
* @new_state: where to store the new state.
* @hint: child of @state used to optimize tree operations.
*
* Verifies if a context starts or ends in @line at @line_pos of after it.
* If the contexts starts or ends here @new_state and @line_pos are updated.
*
* Return value: %FALSE is there are no more contexts in @line.
*/
static gboolean
next_segment (GtkSourceContextEngine *ce,
Segment *state,
LineInfo *line,
gint *line_pos,
Segment **new_state,
Segment **hint)
{
gint pos = *line_pos;
g_assert (!(*hint) || (*hint)->parent == state);
while (pos <= line->length)
{
DefinitionsIter def_iter;
gboolean context_end_found;
ContextDefinition *child_def;
if (state->context->reg_all)
{
if (!regex_match (state->context->reg_all,
line->text,
line->length,
pos))
{
return FALSE;
}
regex_fetch_pos (state->context->reg_all,
line->text, 0, &pos, NULL);
}
/* Does an ancestor end here? */
if (ANCESTOR_CAN_END_CONTEXT (state->context) &&
ancestor_ends_here (state, line, pos, new_state))
{
segment_extend (state, line->start_at + pos);
*line_pos = pos;
return TRUE;
}
/* Does the current context end here? */
context_end_found = segment_ends_here (state, line, pos);
/* Iter over the definitions we can find in the current
* context. */
definition_iter_init (&def_iter, state->context->definition);
while ((child_def = definition_iter_next (&def_iter)))
{
2006-08-26 17:04:13 -07:00
gboolean try_this = TRUE;
2006-08-26 02:46:29 -07:00
/* If the child definition does not extend the parent
* and the current context could end here we do not
* need to examine this child. */
2006-08-26 17:04:13 -07:00
if (!child_def->extend_parent && context_end_found)
try_this = FALSE;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (child_def->first_line_only && line->start_at != 0)
2006-08-26 17:04:13 -07:00
try_this = FALSE;
if (try_this)
2006-08-26 02:46:29 -07:00
{
/* Does this child definition start a new
* context at the current position? */
if (child_starts_here (ce, state, child_def,
line, &pos, new_state,
hint))
{
*line_pos = pos;
definition_iter_destroy (&def_iter);
return TRUE;
}
}
/* This child does not start here, so we analyze
* another definition. */
}
definition_iter_destroy (&def_iter);
if (context_end_found)
{
/* We have found that the current context could end
* here and that it cannot be extended by a child.
* 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))
{
g_assert (state->end_at >= line->start_at + pos);
/* FIXME: if child may terminate parent */
*new_state = state->parent;
*hint = state;
*line_pos = pos;
return TRUE;
}
}
/* Nothing new at this position, go to next char. */
pos++;
}
return FALSE;
}
/**
* 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.
* Updates hint if new state is different from @state.
*
* Return value: the new state.
*/
static Segment *
check_line_end (Segment *state,
LineInfo *line,
Segment **hint)
{
Segment *current_segment;
Segment *terminating_segment;
g_assert (!(*hint) || (*hint)->parent == state);
/* A context can be terminated by the parent if extend_parent is
* FALSE, so we need to verify the end of all the parents of
* not-extending contexts. */
terminating_segment = NULL;
current_segment = state;
do
{
if (current_segment->context->definition->end_at_line_end)
terminating_segment = current_segment;
current_segment = current_segment->parent;
}
while (ANCESTOR_CAN_END_CONTEXT (current_segment->context));
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;
}
else
{
return state;
}
}
/**
* analyze_line:
*
* @ce: #GtkSourceContextEngine.
* @state: the state at the beginning of line.
* @line: the line.
* @hint: a child of @state around start of line, to make it faster.
*
* Finds contexts at the line and updates the syntax tree on it.
*
* Return value: starting state at the next line.
*/
static Segment *
analyze_line (GtkSourceContextEngine *ce,
Segment *state,
LineInfo *line,
Segment **hint)
{
gint line_pos = 0;
g_assert (SEGMENT_IS_CONTAINER (state));
g_assert (!(*hint) || (*hint)->parent == state);
/* Find the contexts in the line. */
while (line_pos <= line->length)
{
Segment *new_state = NULL;
if (!next_segment (ce, state, line, &line_pos, &new_state, hint))
break;
g_assert (new_state != NULL);
state = new_state;
g_assert (SEGMENT_IS_CONTAINER (state));
}
/* Extend current state to the end of line. */
segment_extend (state, line->start_at + line->length);
g_assert (line_pos <= line->length);
/* 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)
{
state = check_line_end (state, line, hint);
}
/* Extend the segment to the beginning of next line. */
g_assert (SEGMENT_IS_CONTAINER (state));
segment_extend (state, NEXT_LINE_OFFSET (line));
return state;
}
/**
* get_line_info:
*
* @buffer: #GtkTextBuffer.
* @line_start: iterator pointing to the beginning of line.
* @line_start: iterator pointing to the beginning of next line or to the end
* of this line if it's the last line in @buffer.
* @line: #LineInfo structure to be filled.
*
* Retrieves line text from the buffer, finds line terminator and fills
* @line structure.
*/
static void
get_line_info (GtkTextBuffer *buffer,
const GtkTextIter *line_start,
const GtkTextIter *line_end,
LineInfo *line)
{
g_assert (!gtk_text_iter_equal (line_start, line_end));
line->text = gtk_text_buffer_get_slice (buffer, line_start, line_end, TRUE);
line->start_at = gtk_text_iter_get_offset (line_start);
if (!gtk_text_iter_starts_line (line_end))
{
line->eol_length = 0;
line->length = g_utf8_strlen (line->text, -1);
}
else
{
gint eol_index, next_line_index;
pango_find_paragraph_boundary (line->text, -1,
&eol_index,
&next_line_index);
g_assert (eol_index < next_line_index);
line->length = g_utf8_strlen (line->text, eol_index);
line->eol_length = g_utf8_strlen (line->text + eol_index, -1);
}
g_assert (gtk_text_iter_get_offset (line_end) ==
line->start_at + line->length + line->eol_length);
}
/**
* line_info_destroy:
*
* @line: #LineInfo.
*
* Destroys data allocated by get_line_info().
*/
static void
line_info_destroy (LineInfo *line)
{
g_free (line->text);
}
/**
* segment_tree_zero_len:
*
* @ce: #GtkSoucreContextEngine.
*
* Erases syntax tree and sets root segment length to zero.
* It's a shortcut for case when all the text is deleted from
* the buffer.
*/
static void
segment_tree_zero_len (GtkSourceContextEngine *ce)
{
Segment *root = ce->priv->root_segment;
segment_destroy_children (ce, root);
root->start_at = root->end_at = 0;
CHECK_TREE (ce);
}
#ifdef ENABLE_CHECK_TREE
static Segment *
get_segment_at_offset_slow_ (Segment *segment,
gint offset)
{
Segment *child;
start:
if (!segment->parent && offset == segment->end_at)
return segment;
if (segment->start_at > offset)
{
g_assert (segment->parent != NULL);
segment = segment->parent;
goto start;
}
if (segment->start_at == offset)
{
if (segment->children && segment->children->start_at == offset)
{
segment = segment->children;
goto start;
}
return segment;
}
if (segment->end_at <= offset && segment->parent)
{
if (segment->next)
{
if (segment->next->start_at > offset)
return segment->parent;
segment = segment->next;
}
else
{
segment = segment->parent;
}
goto start;
}
for (child = segment->children; child != NULL; child = child->next)
{
if (child->start_at == offset)
{
segment = child;
goto start;
}
if (child->end_at <= offset)
continue;
if (child->start_at > offset)
break;
segment = child;
goto start;
}
return segment;
}
#endif /* ENABLE_CHECK_TREE */
#define SEGMENT_IS_ZERO_LEN_AT(s,o) ((s)->start_at == (o) && (s)->end_at == (o))
#define SEGMENT_CONTAINS(s,o) ((s)->start_at <= (o) && (s)->end_at > (o))
#define SEGMENT_DISTANCE(s,o) (MIN (ABS ((s)->start_at - (o)), ABS ((s)->end_at - (o))))
static Segment *
get_segment_in_ (Segment *segment,
gint offset)
{
Segment *child;
g_assert (segment->start_at <= offset && segment->end_at > offset);
if (!segment->children)
return segment;
if (segment->children == segment->last_child)
{
if (SEGMENT_IS_ZERO_LEN_AT (segment->children, offset))
return segment->children;
if (SEGMENT_CONTAINS (segment->children, offset))
return get_segment_in_ (segment->children, offset);
return segment;
}
if (segment->children->start_at > offset || segment->last_child->end_at < offset)
return segment;
if (SEGMENT_DISTANCE (segment->children, offset) >= SEGMENT_DISTANCE (segment->last_child, offset))
{
for (child = segment->children; child; child = child->next)
{
if (child->start_at > offset)
return segment;
if (SEGMENT_IS_ZERO_LEN_AT (child, offset))
return child;
if (SEGMENT_CONTAINS (child, offset))
return get_segment_in_ (child, offset);
}
}
else
{
for (child = segment->last_child; child; child = child->prev)
{
if (SEGMENT_IS_ZERO_LEN_AT (child, offset))
{
while (child->prev && SEGMENT_IS_ZERO_LEN_AT (child->prev, offset))
child = child->prev;
return child;
}
if (child->end_at <= offset)
return segment;
if (SEGMENT_CONTAINS (child, offset))
return get_segment_in_ (child, offset);
}
}
return segment;
}
/* assumes zero-length segments can't have children */
static Segment *
get_segment_ (Segment *segment,
gint offset)
{
if (segment->parent)
{
if (!SEGMENT_CONTAINS (segment->parent, offset))
return get_segment_ (segment->parent, offset);
}
else
{
g_assert (offset >= segment->start_at);
g_assert (offset <= segment->end_at);
}
if (SEGMENT_CONTAINS (segment, offset))
return get_segment_in_ (segment, offset);
if (SEGMENT_IS_ZERO_LEN_AT (segment, offset))
{
while (segment->prev && SEGMENT_IS_ZERO_LEN_AT (segment->prev, offset))
segment = segment->prev;
return segment;
}
if (offset < segment->start_at)
{
while (segment->prev && segment->prev->start_at > offset)
segment = segment->prev;
g_assert (!segment->prev || segment->prev->start_at <= offset);
if (!segment->prev)
return segment->parent;
if (segment->prev->end_at > offset)
return get_segment_in_ (segment->prev, offset);
if (segment->prev->end_at == offset)
{
if (SEGMENT_IS_ZERO_LEN_AT (segment->prev, offset))
{
segment = segment->prev;
while (segment->prev && SEGMENT_IS_ZERO_LEN_AT (segment->prev, offset))
segment = segment->prev;
return segment;
}
return segment->parent;
}
/* segment->prev->end_at < offset */
return segment->parent;
}
/* offset >= segment->end_at, not zero-length */
while (segment->next)
{
if (SEGMENT_IS_ZERO_LEN_AT (segment->next, offset))
return segment->next;
if (segment->next->end_at > offset)
{
if (segment->next->start_at <= offset)
return get_segment_in_ (segment->next, offset);
else
return segment->parent;
}
segment = segment->next;
}
return segment->parent;
}
#undef SEGMENT_IS_ZERO_LEN_AT
#undef SEGMENT_CONTAINS
#undef SEGMENT_DISTANCE
/**
* get_segment_at_offset:
*
* @ce: #GtkSoucreContextEngine.
* @hint: segment to start search from or NULL.
* @offset: the offset.
*
* Finds the deepest segment "at @offset".
* More precisely, it returns toplevel segment if
* @offset is equal to length of buffer; or non-zero-length
* segment which contains character at @offset; or zero-length
* segment at @offset. In case when there are several zero-length
* segments, it returns the first one.
*/
static Segment *
get_segment_at_offset (GtkSourceContextEngine *ce,
Segment *hint,
gint offset)
{
Segment *result;
if (offset == ce->priv->root_segment->end_at)
return ce->priv->root_segment;
if (!hint || hint == ce->priv->root_segment)
{
static int c;
g_print ("searching from root %d\n", ++c);
}
result = get_segment_ (hint ? hint : ce->priv->root_segment, offset);
#ifdef ENABLE_CHECK_TREE
g_assert (result == get_segment_at_offset_slow_ (hint, offset));
#endif
return result;
}
/**
* segment_remove:
*
* @ce: #GtkSoucreContextEngine.
* @segment: segment remove.
*
* Removes the segment from syntax tree and frees it.
* It correctly updates parent's children list, not
* like segment_destroy() where caller has to take care
* of tree integrity.
*/
static void
segment_remove (GtkSourceContextEngine *ce,
Segment *segment)
{
if (segment->next)
segment->next->prev = segment->prev;
else
segment->parent->last_child = segment->prev;
if (segment->prev)
segment->prev->next = segment->next;
else
segment->parent->children = segment->next;
/* if ce->priv->hint is being deleted, set it to some
* neighbour segment */
if (ce->priv->hint == segment)
{
if (segment->next)
ce->priv->hint = segment->next;
else if (segment->prev)
ce->priv->hint = segment->prev;
else
ce->priv->hint = segment->parent;
}
segment_destroy (ce, segment);
}
static void
segment_erase_middle_ (GtkSourceContextEngine *ce,
Segment *segment,
gint start,
gint end)
{
Segment *new_segment, *children, *child;
SubPattern *sub_patterns, *sp;
new_segment = segment_new (ce,
segment->parent,
segment->context,
end,
segment->end_at);
segment->end_at = start;
new_segment->next = segment->next;
segment->next = new_segment;
new_segment->prev = segment;
if (new_segment->next)
new_segment->next->prev = new_segment;
else
new_segment->parent->last_child = new_segment;
children = segment->children;
segment->children = NULL;
segment->last_child = NULL;
for (child = children; child != NULL; )
{
Segment *append_to;
Segment *next = child->next;
if (child->start_at < start)
{
g_assert (child->end_at <= start);
append_to = segment;
}
else
{
g_assert (child->start_at >= end);
append_to = new_segment;
}
child->parent = append_to;
if (append_to->last_child)
{
append_to->last_child->next = child;
child->prev = append_to->last_child;
child->next = NULL;
append_to->last_child = child;
}
else
{
child->next = child->prev = NULL;
append_to->last_child = child;
append_to->children = child;
}
child = next;
}
sub_patterns = segment->sub_patterns;
segment->sub_patterns = NULL;
for (sp = sub_patterns; sp != NULL; )
{
SubPattern *next = sp->next;
Segment *append_to;
if (sp->start_at < start)
{
sp->end_at = MIN (sp->end_at, start);
append_to = segment;
}
else
{
g_assert (sp->end_at > end);
sp->start_at = MAX (sp->start_at, end);
append_to = new_segment;
}
sp->next = append_to->sub_patterns;
append_to->sub_patterns = sp;
sp = next;
}
CHECK_SEGMENT_CHILDREN (segment);
CHECK_SEGMENT_CHILDREN (new_segment);
}
/**
* segment_erase_range_:
*
* @ce: #GtkSourceContextEngine.
* @segment: the segment.
* @start: start offset of range to erase.
* @end: end offset of range to erase.
*
* Recurisvely removes segments from [@start, @end] interval
* starting from @segment. If @segment belongs to the range,
* or it's a zero-length segment at @end offset, and it's not
* the toplevel segment, then it's removed from the tree.
* If @segment intersects with the range (unless it's the toplevel
* segment), then its ends are adjusted appropriately, and it's
* split into two if it completely contains the range.
*/
static void
segment_erase_range_ (GtkSourceContextEngine *ce,
Segment *segment,
gint start,
gint end)
{
Segment *child;
g_assert (start < end);
if (segment->start_at == segment->end_at)
{
if (segment->start_at >= start && segment->start_at <= end)
segment_remove (ce, segment);
return;
}
if (segment->start_at > end || segment->end_at < start)
return;
if (segment->start_at >= start && segment->end_at <= end && segment->parent)
{
segment_remove (ce, segment);
return;
}
if (segment->start_at == end)
{
for (child = segment->children; child != NULL && child->start_at == end; )
{
Segment *next = child->next;
segment_erase_range_ (ce, child, start, end);
child = next;
}
}
else if (segment->end_at == start)
{
for (child = segment->last_child; child != NULL && child->end_at == start; )
{
Segment *prev = child->prev;
segment_erase_range_ (ce, child, start, end);
child = prev;
}
}
else
{
for (child = segment->children; child != NULL; )
{
Segment *next = child->next;
segment_erase_range_ (ce, child, start, end);
child = next;
}
}
if (segment->sub_patterns)
{
SubPattern *sub_patterns, *sp;
sub_patterns = segment->sub_patterns;
segment->sub_patterns = NULL;
for (sp = sub_patterns; sp != NULL; )
{
SubPattern *next = sp->next;
if (sp->start_at >= start && sp->end_at <= end)
sub_pattern_free (sp);
else
segment_add_subpattern (segment, sp);
sp = next;
}
}
if (segment->parent)
{
/* Now all children and subpatterns are cleaned up,
* so we only need to split segment properly if its middle
* was erased. Otherwise, only ends need to be adjusted. */
if (segment->start_at < start && segment->end_at > end)
{
segment_erase_middle_ (ce, segment, start, end);
}
else
{
g_assert ((segment->start_at >= start && segment->end_at > end) ||
(segment->start_at < start && segment->end_at <= end));
if (segment->end_at > end)
segment->start_at = end;
else
segment->end_at = start;
}
}
}
/**
* segment_merge:
*
* @ce: #GtkSourceContextEngine.
* @first: first segment.
* @second: second segment.
*
* Merges adjacent segments @first and @second given
* their contexts are equal.
*/
static void
segment_merge (GtkSourceContextEngine *ce,
Segment *first,
Segment *second)
{
Segment *parent;
if (first == second)
return;
g_assert (!SEGMENT_IS_INVALID (first));
g_assert (first->context == second->context);
g_assert (first->end_at == second->start_at);
if (first->parent != second->parent)
segment_merge (ce, first->parent, second->parent);
parent = first->parent;
g_assert (first->next == second);
g_assert (first->parent == second->parent);
g_assert (second != parent->children);
if (second == parent->last_child)
parent->last_child = first;
first->next = second->next;
if (second->next)
second->next->prev = first;
first->end_at = second->end_at;
if (second->children)
{
Segment *child;
for (child = second->children; child != NULL; child = child->next)
child->parent = first;
if (!first->children)
{
g_assert (!first->last_child);
first->children = second->children;
first->last_child = second->last_child;
}
else
{
first->last_child->next = second->children;
second->children->prev = first->last_child;
first->last_child = second->last_child;
}
}
if (second->sub_patterns)
{
if (!first->sub_patterns)
{
first->sub_patterns = second->sub_patterns;
}
else
{
while (second->sub_patterns)
{
SubPattern *sp = second->sub_patterns;
second->sub_patterns = second->sub_patterns->next;
sp->next = first->sub_patterns;
first->sub_patterns = sp;
}
}
}
second->children = NULL;
second->last_child = NULL;
second->sub_patterns = NULL;
segment_destroy (ce, second);
}
/**
* erase_segments:
*
* @ce: #GtkSourceContextEngine.
* @start: start offset of region to erase.
* @end: end offset of region to erase.
* @hint: segment around @start to make it faster.
*
* Erases all non-toplevel segments in the interval
* [@start, @end]. Its action on the tree is roughly
* equivalent to segment_erase_range_(ce->priv->root_segment, start, end)
* (but that does not accept toplevel segment).
*/
static void
erase_segments (GtkSourceContextEngine *ce,
gint start,
gint end,
Segment *hint)
{
Segment *root = ce->priv->root_segment;
Segment *child, *hint_prev;
if (!root->children)
return;
if (!hint)
hint = ce->priv->hint;
if (hint)
while (hint && hint->parent != ce->priv->root_segment)
hint = hint->parent;
if (!hint)
hint = root->children;
hint_prev = hint->prev;
child = hint;
while (child)
{
Segment *next = child->next;
if (child->end_at < start)
{
child = next;
if (next)
ce->priv->hint = next;
continue;
}
if (child->start_at > end)
{
ce->priv->hint = child;
break;
}
segment_erase_range_ (ce, child, start, end);
child = next;
}
child = hint_prev;
while (child)
{
Segment *prev = child->prev;
if (!ce->priv->hint)
ce->priv->hint = child;
if (child->start_at > end)
{
child = prev;
continue;
}
if (child->end_at < start)
{
break;
}
segment_erase_range_ (ce, child, start, end);
child = prev;
}
CHECK_TREE (ce);
}
/**
* update_syntax:
*
* @ce: #GtkSourceContextEngine.
* @end: desired end of region to analyze or NULL.
* @time: maximal amount of time in milliseconds allowed to spend here
* or 0 for 'unlimited'.
*
* Updates syntax tree. If %end is not NULL, then it analyzes
* (reanalyzes invalid areas in) region from start of buffer
* to %end. Otherwise, it analyzes batch of text starting at
* first invalid line.
* In order to avoid blocking ui it uses a timer and stops
* when time elapsed is greater than %time, so analyzed region is
* not necessarily what's requested (unless %time is 0).
*/
/* XXX it needs to be refactored. I'm not doing it now because it's
* not clear whether it does the right thing (it was rewritten two times
* already). */
static void
update_syntax (GtkSourceContextEngine *ce,
const GtkTextIter *end,
gint time)
{
Segment *invalid;
GtkTextIter start_iter, end_iter;
GtkTextIter line_start, line_end;
gint start_offset, end_offset;
gint line_start_offset, line_end_offset;
gint analyzed_end;
GtkTextBuffer *buffer = ce->priv->buffer;
Segment *state = ce->priv->root_segment;
Segment *hint = ce->priv->hint;
GTimer *timer;
context_freeze (ce->priv->root_context);
update_tree (ce);
if (!gtk_text_buffer_get_char_count (buffer))
{
segment_tree_zero_len (ce);
goto out;
}
invalid = get_invalid_segment (ce);
if (!invalid)
goto out;
if (end && invalid->start_at >= gtk_text_iter_get_offset (end))
goto out;
if (end)
{
end_offset = gtk_text_iter_get_offset (end);
start_offset = MIN (end_offset, invalid->start_at);
}
else
{
start_offset = invalid->start_at;
end_offset = gtk_text_buffer_get_char_count (buffer);
}
gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start_offset);
gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end_offset);
if (!gtk_text_iter_starts_line (&start_iter))
{
gtk_text_iter_set_line_offset (&start_iter, 0);
start_offset = gtk_text_iter_get_offset (&start_iter);
}
if (!gtk_text_iter_starts_line (&end_iter))
{
gtk_text_iter_forward_line (&end_iter);
end_offset = gtk_text_iter_get_offset (&end_iter);
}
/* This happens after deleting all text on last line. */
if (start_offset == end_offset)
{
g_assert (end_offset == gtk_text_buffer_get_char_count (buffer));
g_assert (g_slist_length (ce->priv->invalid) == 1);
segment_remove (ce, invalid);
CHECK_TREE (ce);
goto out;
}
/* Main loop */
line_start = start_iter;
line_start_offset = start_offset;
line_end = line_start;
gtk_text_iter_forward_line (&line_end);
line_end_offset = gtk_text_iter_get_offset (&line_end);
analyzed_end = line_end_offset;
timer = g_timer_new ();
while (TRUE)
{
LineInfo line;
gboolean next_line_invalid = FALSE;
gboolean need_invalidate_next = FALSE;
/* Last buffer line. */
if (line_start_offset == line_end_offset)
{
g_assert (line_start_offset == gtk_text_buffer_get_char_count (buffer));
break;
}
/* Analyze the line */
erase_segments (ce, line_start_offset, line_end_offset, ce->priv->hint);
get_line_info (buffer, &line_start, &line_end, &line);
{
invalid = get_invalid_segment (ce);
g_assert (!invalid || invalid->start_at >= line_end_offset);
}
if (!line_start_offset)
state = ce->priv->root_segment;
else
state = get_segment_at_offset (ce,
ce->priv->hint ? ce->priv->hint : state,
line_start_offset - 1);
g_assert (state->context != NULL);
hint = ce->priv->hint;
if (hint && hint->parent != state)
hint = NULL;
state = analyze_line (ce, state, &line, &hint);
CHECK_TREE (ce);
{
invalid = get_invalid_segment (ce);
g_assert (!invalid || invalid->start_at >= line_end_offset);
}
/* XXX this is wrong */
if (hint)
ce->priv->hint = hint;
else
ce->priv->hint = state;
line_info_destroy (&line);
gtk_text_region_add (ce->priv->refresh_region, &line_start, &line_end);
analyzed_end = line_end_offset;
if ((invalid = get_invalid_segment (ce)))
{
GtkTextIter iter;
gtk_text_buffer_get_iter_at_offset (buffer, &iter, invalid->start_at);
gtk_text_iter_set_line_offset (&iter, 0);
if (gtk_text_iter_get_offset (&iter) == line_end_offset)
next_line_invalid = TRUE;
}
if (!next_line_invalid)
{
Segment *old_state;
hint = ce->priv->hint ? ce->priv->hint : state;
old_state = get_segment_at_offset (ce, hint, line_end_offset);
if (old_state->context != state->context)
{
need_invalidate_next = TRUE;
next_line_invalid = TRUE;
}
else
{
segment_merge (ce, state, old_state);
CHECK_TREE (ce);
}
}
if ((time && g_timer_elapsed (timer, NULL) * 1000 > time) ||
line_end_offset >= end_offset ||
(!invalid && !next_line_invalid))
{
if (need_invalidate_next)
insert_range (ce, line_end_offset, 0);
break;
}
if (next_line_invalid)
{
line_start_offset = line_end_offset;
line_start = line_end;
gtk_text_iter_forward_line (&line_end);
line_end_offset = gtk_text_iter_get_offset (&line_end);
}
else
{
gtk_text_buffer_get_iter_at_offset (buffer, &line_start, invalid->start_at);
gtk_text_iter_set_line_offset (&line_start, 0);
line_start_offset = gtk_text_iter_get_offset (&line_start);
line_end = line_start;
gtk_text_iter_forward_line (&line_end);
line_end_offset = gtk_text_iter_get_offset (&line_end);
}
}
if (analyzed_end == gtk_text_buffer_get_char_count (buffer))
{
g_assert (g_slist_length (ce->priv->invalid) <= 1);
if (ce->priv->invalid != NULL)
{
invalid = get_invalid_segment (ce);
segment_remove (ce, invalid);
CHECK_TREE (ce);
}
}
if (!all_analyzed (ce))
install_idle_worker (ce);
gtk_text_iter_set_offset (&end_iter, analyzed_end);
refresh_range (ce, &start_iter, &end_iter, FALSE);
PROFILE (g_print ("analyzed %d chars from %d to %d in %fms\n",
analyzed_end - start_offset, start_offset, analyzed_end,
g_timer_elapsed (timer, NULL) * 1000));
g_timer_destroy (timer);
out:
context_thaw (ce->priv->root_context);
}
/* DEFINITIONS MANAGEMENT ------------------------------------------------- */
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
static DefinitionChild *
definition_child_new (ContextDefinition *definition,
ContextDefinition *child_def,
gboolean is_ref_all)
{
DefinitionChild *ch = g_new0 (DefinitionChild, 1);
ch->is_ref_all = is_ref_all;
ch->definition = child_def;
definition->children = g_slist_append (definition->children, ch);
return ch;
}
static void
definition_child_free (DefinitionChild *ch)
{
g_free (ch);
}
2006-08-26 02:46:29 -07:00
static ContextDefinition *
context_definition_new (const gchar *id,
ContextType type,
ContextDefinition *parent,
const gchar *match,
const gchar *start,
const gchar *end,
const gchar *style,
2006-08-26 17:04:13 -07:00
GtkSourceContextMatchOptions options,
2006-08-26 02:46:29 -07:00
GError **error)
{
ContextDefinition *definition;
gboolean regex_error = FALSE;
gboolean unresolved_error = FALSE;
g_return_val_if_fail (id != NULL, NULL);
switch (type)
{
case CONTEXT_TYPE_SIMPLE:
g_return_val_if_fail (match != NULL, NULL);
g_return_val_if_fail (!end && !start, NULL);
break;
case CONTEXT_TYPE_CONTAINER:
g_return_val_if_fail (!match, NULL);
g_return_val_if_fail (!end || start, NULL);
break;
}
definition = g_new0 (ContextDefinition, 1);
if (match)
{
definition->u.match = regex_new (match, EGG_REGEX_ANCHORED, error);
if (!definition->u.match)
{
regex_error = TRUE;
}
else if (!definition->u.match->resolved)
{
unresolved_error = TRUE;
regex_unref (definition->u.match);
definition->u.match = NULL;
}
}
if (start)
{
definition->u.start_end.start = regex_new (start, EGG_REGEX_ANCHORED, error);
if (!definition->u.start_end.start)
{
regex_error = TRUE;
}
else if (!definition->u.start_end.start->resolved)
{
unresolved_error = TRUE;
regex_unref (definition->u.start_end.start);
definition->u.start_end.start = NULL;
}
}
if (end)
{
definition->u.start_end.end = regex_new (end, EGG_REGEX_ANCHORED, error);
if (!definition->u.start_end.end)
regex_error = TRUE;
}
if (unresolved_error)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_START_REF,
"context '%s' cannot contain a \\%%{...@start} command",
id);
regex_error = TRUE;
}
if (regex_error)
{
g_free (definition);
return NULL;
}
definition->id = g_strdup (id);
definition->style = g_strdup (style);
definition->type = type;
2006-08-26 17:04:13 -07:00
definition->extend_parent = (options & GTK_SOURCE_CONTEXT_EXTEND_PARENT) != 0;
definition->end_at_line_end = (options & GTK_SOURCE_CONTEXT_END_AT_LINE_END) != 0;
definition->first_line_only = (options & GTK_SOURCE_CONTEXT_FIRST_LINE_ONLY) != 0;
2006-08-26 02:46:29 -07:00
definition->children = NULL;
definition->sub_patterns = NULL;
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
definition->n_sub_patterns = 0;
2006-08-26 02:46:29 -07:00
/* Main contexts (i.e. the contexts with id "language:language")
* should have extend-parent="true" and end-at-line-end="false". */
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (!parent && egg_regex_match_simple ("^(.+):\\1$", id, 0, 0))
2006-08-26 02:46:29 -07:00
{
2006-08-26 17:04:13 -07:00
if (definition->end_at_line_end)
2006-08-26 02:46:29 -07:00
{
g_warning ("end-at-line-end should be "
"\"false\" for main contexts (id: %s)",
id);
definition->end_at_line_end = FALSE;
}
2006-08-26 17:04:13 -07:00
if (!definition->extend_parent)
2006-08-26 02:46:29 -07:00
{
g_warning ("extend-parent should be "
"\"true\" for main contexts (id: %s)",
id);
definition->extend_parent = TRUE;
}
}
return definition;
}
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
static GtkSourceContextMatchOptions
context_definition_get_options (ContextDefinition *definition)
{
GtkSourceContextMatchOptions options = 0;
if (definition->extend_parent)
options |= GTK_SOURCE_CONTEXT_EXTEND_PARENT;
if (definition->end_at_line_end)
options |= GTK_SOURCE_CONTEXT_END_AT_LINE_END;
if (definition->first_line_only)
options |= GTK_SOURCE_CONTEXT_FIRST_LINE_ONLY;
return options;
}
static ContextDefinition *
context_definition_copy (GtkSourceContextEngine *ce,
ContextDefinition *definition,
ContextDefinition *parent,
const char *style,
GError **error)
{
ContextDefinition *copy;
gchar *id;
GtkSourceContextMatchOptions options;
const gchar *match = NULL;
const gchar *start = NULL, *end = NULL;
switch (definition->type)
{
case CONTEXT_TYPE_SIMPLE:
match = regex_get_pattern (definition->u.match);
break;
case CONTEXT_TYPE_CONTAINER:
if (definition->u.start_end.start)
start = regex_get_pattern (definition->u.start_end.start);
if (definition->u.start_end.end)
end = regex_get_pattern (definition->u.start_end.end);
break;
default:
g_return_val_if_reached (NULL);
}
DEBUG ({
g_print ("match: %s\n", match ? match : "(null)");
g_print ("start: %s\n", start ? start : "(null)");
g_print ("end: %s\n", end ? end : "(null)");
});
id = g_strdup_printf ("%s@%s@%s", ce->priv->id, parent->id, definition->id);
if (g_hash_table_lookup (ce->priv->definitions, id) != NULL)
{
guint i = 1;
while (TRUE)
{
g_free (id);
id = g_strdup_printf ("%s@%s@%s@%d", ce->priv->id, parent->id, definition->id, i);
if (g_hash_table_lookup (ce->priv->definitions, id) == NULL)
break;
++i;
}
}
options = context_definition_get_options (definition);
copy = context_definition_new (id, definition->type, parent,
match, start, end,
style, options, error);
g_free (id);
return copy;
}
2006-08-26 02:46:29 -07:00
static void
context_definition_free (ContextDefinition *definition)
{
GSList *sub_pattern_list;
if (definition == NULL)
return;
switch (definition->type)
{
case CONTEXT_TYPE_SIMPLE:
regex_unref (definition->u.match);
break;
case CONTEXT_TYPE_CONTAINER:
regex_unref (definition->u.start_end.start);
regex_unref (definition->u.start_end.end);
break;
}
sub_pattern_list = definition->sub_patterns;
while (sub_pattern_list != NULL)
{
SubPatternDefinition *sp_def = sub_pattern_list->data;
#ifdef NEED_DEBUG_ID
g_free (sp_def->id);
#endif
g_free (sp_def->style);
if (sp_def->is_named)
g_free (sp_def->u.name);
g_free (sp_def);
sub_pattern_list = sub_pattern_list->next;
}
g_slist_free (definition->sub_patterns);
g_free (definition->id);
g_free (definition->style);
regex_unref (definition->reg_all);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
g_slist_foreach (definition->children, (GFunc) definition_child_free, NULL);
2006-08-26 02:46:29 -07:00
g_slist_free (definition->children);
g_free (definition);
}
static void
definition_iter_init (DefinitionsIter *iter,
ContextDefinition *definition)
{
iter->children_stack = g_slist_prepend (NULL, definition->children);
}
static void
definition_iter_destroy (DefinitionsIter *iter)
{
g_slist_free (iter->children_stack);
}
static ContextDefinition *
definition_iter_next (DefinitionsIter *iter)
{
GSList *children_list;
if (!iter->children_stack)
return NULL;
children_list = iter->children_stack->data;
if (children_list == NULL)
{
iter->children_stack = g_slist_delete_link (iter->children_stack,
iter->children_stack);
return definition_iter_next (iter);
}
else
{
DefinitionChild *curr_child = children_list->data;
ContextDefinition *definition = curr_child->definition;
children_list = g_slist_next (children_list);
iter->children_stack->data = children_list;
if (curr_child->is_ref_all)
{
iter->children_stack = g_slist_prepend (iter->children_stack,
definition->children);
return definition_iter_next (iter);
}
else
{
return definition;
}
}
}
gboolean
_gtk_source_context_engine_define_context (GtkSourceContextEngine *ce,
const gchar *id,
const gchar *parent_id,
const gchar *match_regex,
const gchar *start_regex,
const gchar *end_regex,
const gchar *style,
2006-08-26 17:04:13 -07:00
GtkSourceContextMatchOptions options,
2006-08-26 02:46:29 -07:00
GError **error)
{
ContextDefinition *definition, *parent = NULL;
ContextType type;
gboolean wrong_args = FALSE;
g_return_val_if_fail (GTK_IS_SOURCE_CONTEXT_ENGINE (ce), FALSE);
g_return_val_if_fail (id != NULL, FALSE);
/* If the id is already present in the hashtable it is a duplicate,
* so we report the error (probably there is a duplicate id in the
* XML lang file) */
if (LOOKUP_DEFINITION (ce, id) != NULL)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_DUPLICATED_ID,
"duplicated context id '%s'", id);
return FALSE;
}
if (match_regex != NULL)
type = CONTEXT_TYPE_SIMPLE;
else
type = CONTEXT_TYPE_CONTAINER;
/* Check if the arguments passed are exactly what we expect, no more, no less. */
switch (type)
{
case CONTEXT_TYPE_SIMPLE:
if (start_regex || end_regex)
wrong_args = TRUE;
break;
case CONTEXT_TYPE_CONTAINER:
if (match_regex)
wrong_args = TRUE;
break;
}
if (wrong_args)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_ARGS,
"insufficient or redunduant arguments creating "
"the context '%s'", id);
return FALSE;
}
if (!parent_id)
{
parent = NULL;
}
else
{
parent = LOOKUP_DEFINITION (ce, parent_id);
g_return_val_if_fail (parent != NULL, FALSE);
}
definition = context_definition_new (id, type, parent, match_regex,
start_regex, end_regex, style,
2006-08-26 17:04:13 -07:00
options, error);
2006-08-26 02:46:29 -07:00
if (!definition)
return FALSE;
g_hash_table_insert (ce->priv->definitions, g_strdup (id), definition);
if (parent)
definition_child_new (parent, definition, FALSE);
return TRUE;
}
gboolean
_gtk_source_context_engine_add_sub_pattern (GtkSourceContextEngine *ce,
const gchar *id,
const gchar *parent_id,
const gchar *name,
const gchar *where,
const gchar *style,
GError **error)
{
ContextDefinition *parent;
SubPatternDefinition *sp_def;
SubPatternWhere where_num;
gint number;
g_return_val_if_fail (GTK_IS_SOURCE_CONTEXT_ENGINE (ce), FALSE);
g_return_val_if_fail (id != NULL, FALSE);
g_return_val_if_fail (parent_id != NULL, FALSE);
g_return_val_if_fail (name != NULL, FALSE);
/* If the id is already present in the hashtable it is a duplicate,
* so we report the error (probably there is a duplicate id in the
* XML lang file) */
if (LOOKUP_DEFINITION (ce, id) != NULL)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_DUPLICATED_ID,
"duplicated context id '%s'", id);
return FALSE;
}
parent = LOOKUP_DEFINITION (ce, parent_id);
g_return_val_if_fail (parent != NULL, FALSE);
if (!where || !where[0] || !strcmp (where, "default"))
where_num = SUB_PATTERN_WHERE_DEFAULT;
else if (!strcmp (where, "start"))
where_num = SUB_PATTERN_WHERE_START;
else if (!strcmp (where, "end"))
where_num = SUB_PATTERN_WHERE_END;
else
where_num = (SubPatternWhere) -1;
if ((parent->type == CONTEXT_TYPE_SIMPLE && where_num != SUB_PATTERN_WHERE_DEFAULT) ||
(parent->type == CONTEXT_TYPE_CONTAINER && where_num == SUB_PATTERN_WHERE_DEFAULT))
{
where_num = (SubPatternWhere) -1;
}
if (where_num == (SubPatternWhere) -1)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_WHERE,
"invalid location ('%s') for sub pattern '%s'",
where, id);
return FALSE;
}
sp_def = g_new0 (SubPatternDefinition, 1);
#ifdef NEED_DEBUG_ID
sp_def->id = g_strdup (id);
#endif
sp_def->style = g_strdup (style);
sp_def->where = where_num;
number = sub_pattern_to_int (name);
if (number < 0)
{
sp_def->is_named = TRUE;
sp_def->u.name = g_strdup (name);
}
else
{
sp_def->is_named = FALSE;
sp_def->u.num = number;
}
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
parent->sub_patterns = g_slist_append (parent->sub_patterns, sp_def);
sp_def->index = parent->n_sub_patterns++;
2006-08-26 02:46:29 -07:00
return TRUE;
}
gboolean
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
_gtk_source_context_engine_add_ref (GtkSourceContextEngine *ce,
const gchar *parent_id,
const gchar *ref_id,
GtkSourceContextRefOptions options,
const gchar *style,
gboolean all,
GError **error)
2006-08-26 02:46:29 -07:00
{
ContextDefinition *parent;
ContextDefinition *ref;
g_return_val_if_fail (parent_id != NULL, FALSE);
g_return_val_if_fail (ref_id != NULL, FALSE);
g_return_val_if_fail (GTK_IS_SOURCE_CONTEXT_ENGINE (ce), FALSE);
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (all && (options & (GTK_SOURCE_CONTEXT_IGNORE_STYLE | GTK_SOURCE_CONTEXT_OVERRIDE_STYLE)))
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_STYLE,
"can't override style for '%s' reference",
ref_id);
return FALSE;
}
2006-08-26 02:46:29 -07:00
/* If the id is already present in the hashtable it is a duplicate,
* so we report the error (probably there is a duplicate id in the
* XML lang file). */
ref = LOOKUP_DEFINITION (ce, ref_id);
if (!ref)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_REF,
"invalid id '%s', the definition does not exist",
ref_id);
return FALSE;
}
if (all && ref->type != CONTEXT_TYPE_CONTAINER)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_REF,
"context '%s' is not a container context",
ref_id);
return FALSE;
}
parent = LOOKUP_DEFINITION (ce, parent_id);
g_return_val_if_fail (parent != NULL, FALSE);
if (parent->type != CONTEXT_TYPE_CONTAINER)
{
g_set_error (error,
GTK_SOURCE_CONTEXT_ENGINE_ERROR,
GTK_SOURCE_CONTEXT_ENGINE_ERROR_INVALID_PARENT,
"invalid parent type for the context '%s'",
ref_id);
return FALSE;
}
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
if (options & (GTK_SOURCE_CONTEXT_IGNORE_STYLE | GTK_SOURCE_CONTEXT_OVERRIDE_STYLE))
{
ref = context_definition_copy (ce, ref, parent, style, error);
if (!ref)
return FALSE;
g_hash_table_insert (ce->priv->definitions, g_strdup (ref->id), ref);
}
2006-08-26 02:46:29 -07:00
definition_child_new (parent, ref, all);
return TRUE;
}
static void
add_escape_ref (ContextDefinition *definition,
GtkSourceContextEngine *ce)
{
GError *error = NULL;
/* XXX */
if (definition->type != CONTEXT_TYPE_CONTAINER)
return;
_gtk_source_context_engine_add_ref (ce, definition->id,
"gtk-source-context-engine-escape",
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
0, NULL, FALSE, &error);
2006-08-26 02:46:29 -07:00
if (error)
goto out;
_gtk_source_context_engine_add_ref (ce, definition->id,
"gtk-source-context-engine-line-escape",
Synced with upstream 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/automake.lang, gtksourceview/language-specs/check.sh, gtksourceview/language-specs/Makefile.am: new lang file for Makefile.am. * gtksourceview/language-specs/c.lang: override style for line-continue in macros; use def:string context. * gtksourceview/language-specs/def.lang: renamed 'c-style-escape' to 'escape', it's not really 'C style'; added 'escape' style to 'line-continue' context; added 'string' and 'single-quoted-string' contexts. * gtksourceview/language-specs/javascript.lang: replaced def:c-style-escape with def:escape. * gtksourceview/language-specs/language2.rng: added optional style-ref and ignore-style attributes to <context ref=""> tags. * gtksourceview/gtksourcecontextengine.[ch], gtksourceview/gtksourcelanguage-parser-2.c: made it possible to override style from referenced context: <context ref="some-context" style-ref="some-style"> means "use context some-context with style some-style", and ignore-style attribute means "use no style in this context". 2006-08-27 Yevgen Muntyan <muntyan@tamu.edu> * gtksourceview/language-specs/Makefile.am: install style scheme into $prefix/gtksourceview-2.0/styles dir. * gtksourceview/gtksourcecontextengine.c: fixed subpatterns handling (subpatterns tags were applied randomly); made high-priority one-time idle called more often, which hopefully make it look nicer; (gtk_source_context_engine_update_highlight): highlight as much as possible even if some part of requested area is not analyzed yet. * gtksourceview/gtksourcelanguage-parser-2.c: fixed two leaks. * gtksourceview/gtksourcelanguagesmanager.c, gtksourceview/gtksourcestylescheme.h, gtksourceview/gtksourceview.c: _gtk_source_style_scheme_get_default() - temporary workaround for no-builtin-scheme thing.
2006-08-27 17:11:56 -07:00
0, NULL, FALSE, &error);
2006-08-26 02:46:29 -07:00
out:
if (error)
{
g_warning ("%s", error->message);
g_error_free (error);
}
}
static void
prepend_definition (G_GNUC_UNUSED gchar *id,
ContextDefinition *definition,
GSList **list)
{
*list = g_slist_prepend (*list, definition);
}
/* Only for lang files version 1, do not use it */
/* It's called after lang file is parsed. It creates two special contexts
contexts and puts them into every container context defined. These contexts
are 'x.' and 'x$', where 'x' is the escape char. In this way, patterns from
lang files are matched only if match doesn't start with escaped char, and
escaped char in the end of line means that the current contexts extends to the
next line. */
/* XXX unicode */
void
_gtk_source_context_engine_set_escape_char (GtkSourceContextEngine *ce,
gunichar escape_char)
{
GError *error = NULL;
char buf[10];
gint len;
char *escaped, *pattern;
GSList *definitions = NULL;
g_return_if_fail (GTK_IS_SOURCE_CONTEXT_ENGINE (ce));
g_return_if_fail (escape_char != 0);
len = g_unichar_to_utf8 (escape_char, buf);
g_return_if_fail (len > 0);
escaped = egg_regex_escape_string (buf, 1);
pattern = g_strdup_printf ("%s.", escaped);
g_hash_table_foreach (ce->priv->definitions, (GHFunc) prepend_definition, &definitions);
definitions = g_slist_reverse (definitions);
if (!_gtk_source_context_engine_define_context (ce, "gtk-source-context-engine-escape",
NULL, pattern, NULL, NULL, NULL,
2006-08-26 17:04:13 -07:00
GTK_SOURCE_CONTEXT_EXTEND_PARENT,
&error))
2006-08-26 02:46:29 -07:00
goto out;
g_free (pattern);
pattern = g_strdup_printf ("%s$", escaped);
if (!_gtk_source_context_engine_define_context (ce, "gtk-source-context-engine-line-escape",
NULL, NULL, pattern, "^", NULL,
2006-08-26 17:04:13 -07:00
GTK_SOURCE_CONTEXT_EXTEND_PARENT,
&error))
2006-08-26 02:46:29 -07:00
goto out;
g_slist_foreach (definitions, (GFunc) add_escape_ref, ce);
out:
if (error)
{
g_warning ("%s", error->message);
g_error_free (error);
}
g_free (pattern);
g_free (escaped);
g_slist_free (definitions);
}
/* DEBUG CODE ------------------------------------------------------------- */
#ifdef ENABLE_CHECK_TREE
static void
check_segment (GtkSourceContextEngine *ce,
Segment *segment)
{
Segment *child;
g_assert (segment != NULL);
g_assert (segment->start_at <= segment->end_at);
g_assert (!segment->next || segment->next->start_at >= segment->end_at);
if (SEGMENT_IS_INVALID (segment))
g_assert (g_slist_find (ce->priv->invalid, segment) != NULL);
else
g_assert (g_slist_find (ce->priv->invalid, segment) == NULL);
if (segment->children)
g_assert (!SEGMENT_IS_INVALID (segment) && SEGMENT_IS_CONTAINER (segment));
for (child = segment->children; child != NULL; child = child->next)
{
g_assert (child->parent == segment);
g_assert (child->start_at >= segment->start_at);
g_assert (child->end_at <= segment->end_at);
g_assert (child->prev || child == segment->children);
g_assert (child->next || child == segment->last_child);
check_segment (ce, child);
}
}
static void
check_context_hash_cb (const char *text,
Context *context,
gpointer user_data)
{
struct {
Context *parent;
ContextDefinition *definition;
} *data = user_data;
g_assert (text != NULL);
g_assert (context != NULL);
g_assert (context->definition == data->definition);
g_assert (context->parent == data->parent);
}
static void
check_context (Context *context)
{
ContextPtr *ptr;
for (ptr = context->children; ptr != NULL; ptr = ptr->next)
{
if (ptr->fixed)
{
g_assert (ptr->u.context->parent == context);
g_assert (ptr->u.context->definition == ptr->definition);
check_context (ptr->u.context);
}
else
{
struct {
Context *parent;
ContextDefinition *definition;
} data = {context, ptr->definition};
g_hash_table_foreach (ptr->u.hash,
(GHFunc) check_context_hash_cb,
&data);
}
}
}
static void
check_regex (void)
{
static gboolean done;
if (!done)
{
g_assert (!find_single_byte_escape ("gfregerg"));
g_assert (!find_single_byte_escape ("\\\\C"));
g_assert (find_single_byte_escape ("\\C"));
g_assert (find_single_byte_escape ("ewfwefwefwef\\Cwefwefwefwe"));
g_assert (find_single_byte_escape ("ewfwefwefwef\\\\Cwefw\\Cefwefwe"));
g_assert (!find_single_byte_escape ("ewfwefwefwef\\\\Cwefw\\\\Cefwefwe"));
done = TRUE;
}
}
static void
CHECK_TREE (GtkSourceContextEngine *ce)
{
Segment *root = ce->priv->root_segment;
check_regex ();
g_assert (root->start_at == 0);
if (ce->priv->invalid_region.empty)
g_assert (root->end_at == gtk_text_buffer_get_char_count (ce->priv->buffer));
g_assert (!root->parent);
check_segment (ce, root);
g_assert (!ce->priv->root_context->parent);
g_assert (root->context == ce->priv->root_context);
check_context (ce->priv->root_context);
}
static void
CHECK_SEGMENT_CHILDREN (Segment *segment)
{
Segment *ch;
g_assert (segment != NULL);
CHECK_SEGMENT_LIST (segment->parent);
for (ch = segment->children; ch != NULL; ch = ch->next)
{
g_assert (ch->parent == segment);
g_assert (ch->start_at <= ch->end_at);
g_assert (!ch->next || ch->next->start_at >= ch->end_at);
g_assert (ch->start_at >= segment->start_at);
g_assert (ch->end_at <= segment->end_at);
g_assert (ch->prev || ch == segment->children);
g_assert (ch->next || ch == segment->last_child);
}
}
static void
CHECK_SEGMENT_LIST (Segment *segment)
{
Segment *ch;
if (!segment)
return;
for (ch = segment->children; ch != NULL; ch = ch->next)
{
g_assert (ch->parent == segment);
g_assert (ch->start_at <= ch->end_at);
g_assert (!ch->next || ch->next->start_at >= ch->end_at);
g_assert (ch->prev || ch == segment->children);
g_assert (ch->next || ch == segment->last_child);
}
}
#endif /* ENABLE_CHECK_TREE */