From fed6c4c0982884a531399f1653e603aa449f89bc Mon Sep 17 00:00:00 2001 From: Yevgen Muntyan <17531749+muntyan@users.noreply.github.com> Date: Mon, 2 Oct 2006 01:15:27 -0500 Subject: [PATCH] Upstream changes: mime types and stuff moved to properties --- .../gtksourceview/gtksourcecontextengine.c | 201 ++++++++++++++---- .../gtksourceview/gtksourcelanguage-private.h | 9 +- moo/mooedit/gtksourceview/gtksourcelanguage.c | 200 ++++++++--------- moo/mooedit/gtksourceview/gtksourcelanguage.h | 5 +- moo/mooedit/language-specs/changelog.lang | 7 +- moo/mooedit/language-specs/diff.lang | 6 +- moo/mooedit/language-specs/html.lang | 9 +- moo/mooedit/language-specs/javascript.lang | 6 +- moo/mooedit/language-specs/language2.rng | 44 ++-- moo/mooedit/language-specs/latex.lang | 9 +- moo/mooedit/language-specs/m4.lang | 9 +- moo/mooedit/language-specs/makefile.lang | 10 +- moo/mooedit/language-specs/ms.lang | 10 +- moo/mooedit/language-specs/python.lang | 9 +- moo/mooedit/language-specs/sh.lang | 10 +- moo/mooedit/language-specs/xml.lang | 11 +- moo/mooedit/language-specs/yacc.lang | 14 +- moo/mooedit/moolang.c | 6 +- 18 files changed, 347 insertions(+), 228 deletions(-) diff --git a/moo/mooedit/gtksourceview/gtksourcecontextengine.c b/moo/mooedit/gtksourceview/gtksourcecontextengine.c index 5fba2277..0d88df9a 100644 --- a/moo/mooedit/gtksourceview/gtksourcecontextengine.c +++ b/moo/mooedit/gtksourceview/gtksourcecontextengine.c @@ -19,6 +19,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* FIXME adjacent invalid segments: is it a problem? it should be taken care of, + * but need to check anyway (it's really impossible to *test*) */ + #include "gtksourceview-i18n.h" #include "gtksourcecontextengine.h" #include "gtktextregion.h" @@ -61,8 +64,11 @@ #define FIRST_UPDATE_TIME_SLICE 10 /* Priority of long running idle which is used to analyze whole buffer, if * the engine wasn't quick enough to analyze it in one shot. */ -/* FIXME lower this priority */ -#define INCREMENTAL_UPDATE_PRIORITY GTK_TEXT_VIEW_PRIORITY_VALIDATE +/* FIXME this priority is low, since we don't want to block other gui stuff. + * But, e.g. if we have a big file, and scroll down, we do want the engine + * to analyze quickly. Perhaps we want to reinstall first_update in case + * of expose events or something. */ +#define INCREMENTAL_UPDATE_PRIORITY G_PRIORITY_LOW /* Maximal amount of time allowed to spent in one cycle of background idle. */ #define INCREMENTAL_UPDATE_TIME_SLICE 30 @@ -242,6 +248,7 @@ struct _Context GtkTextTag **subpattern_tags; guint ref_count; + /* see context_freeze() */ guint frozen : 1; /* Do all the ancestors extend their parent? */ @@ -1123,20 +1130,16 @@ find_insertion_place (Segment *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; - } +#ifdef ENABLE_CHECK_TREE + g_assert (!segment->children || + !SEGMENT_IS_INVALID (segment->children) || + segment->children->start_at > offset); +#endif + + *parent = segment; + *next = segment->children; return; } @@ -1655,7 +1658,7 @@ delete_range_ (GtkSourceContextEngine *ce, { g_return_if_fail (start < end); - /* XXX it may make two invalid segments adjacent, and we can get crash */ + /* FIXME adjacent invalid segments? */ erase_segments (ce, start, end, NULL); fix_offsets_delete_ (ce->priv->root_segment, start, end - start, ce->priv->hint); @@ -1815,10 +1818,6 @@ update_tree (GtkSourceContextEngine *ce) * Makes sure the area is analyzed and highlighted. If %asynchronous * is FALSE, then it queues idle worker. */ -/* 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 gtk_source_context_engine_update_highlight (GtkSourceEngine *engine, const GtkTextIter *start, @@ -2750,7 +2749,6 @@ can_apply_match (Context *state, * 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 @@ -3101,6 +3099,22 @@ context_freeze_hash_cb (G_GNUC_UNUSED gpointer text, context_freeze (context); } +/** + * context_freeze: + * + * @context: the context. + * + * Recursively increments reference count in context and its children, + * and marks them, so context_thaw is able to correctly decrement + * reference count. + * This function is for update_syntax: we want to preserve existing + * contexts when possible, and update_syntax erases contexts from + * reanalyzed lines; so to avoid destructing and recreating contexts + * every time, we need to increment reference count on existing contexts, + * and decrement it when we are done with analysis, so no more needed + * contexts go away. Keeping a list of referenced contexts is painful + * or slow, so we just reference all contexts present at the moment. + */ static void context_freeze (Context *ctx) { @@ -3133,6 +3147,14 @@ get_child_contexts_hash_cb (G_GNUC_UNUSED gpointer text, *list = g_slist_prepend (*list, context); } +/** + * context_thaw: + * + * @context: the context. + * + * Recursively decrements reference count in context and its children, + * if it was incremented by context_freeze. + */ static void context_thaw (Context *ctx) { @@ -3230,6 +3252,22 @@ create_child_context (Context *parent, return context; }; +/** + * segment_new: + * + * @ce: the engine. + * @parent: parent segment (NULL for the root segment). + * @context: context for this segment (NULL for invalid segments). + * @start_at: start offset. + * @end_at: end offset. + * @is_start: is_start flag. + * + * Creates a new segment structure. It doesn't take care about + * parent or siblings, create_segment() is the function to + * create new segments in the tree. + * + * Returns: newly created segment. + */ static Segment * segment_new (GtkSourceContextEngine *ce, Segment *parent, @@ -3323,6 +3361,20 @@ find_segment_position_backward_ (Segment *segment, } } +/** + * find_segment_position: + * + * @parent: parent segment (not NULL). + * @hint: segment somewhere near new segment position. + * @start_at: start offset. + * @end_at: end offset. + * @prev: location to return previous sibling. + * @next: location to return next sibling. + * + * Finds siblings of a new segment to be created at interval + * (start_at, end_at). It uses hint to avoid walking whole + * parent->children list. + */ static void find_segment_position (Segment *parent, Segment *hint, @@ -3362,6 +3414,21 @@ find_segment_position (Segment *parent, return find_segment_position_backward_ (hint, start_at, end_at, prev, next); } +/** + * create_segment: + * + * @ce: the engine. + * @parent: parent segment (NULL for the root segment). + * @context: context for this segment (NULL for invalid segments). + * @start_at: start offset. + * @end_at: end offset. + * @is_start: is_start flag. + * @hint: a segment somewhere near new one, to omtimize search. + * + * Creates a new segment and inserts it into the tree. + * + * Returns: newly created segment. + */ static Segment * create_segment (GtkSourceContextEngine *ce, Segment *parent, @@ -3417,6 +3484,14 @@ create_segment (GtkSourceContextEngine *ce, return segment; } +/** + * segment_extend: + * + * @state: the semgent. + * @end_at: new end offset. + * + * Updates end offset in the segment and its ancestors. + */ static void segment_extend (Segment *state, gint end_at) @@ -3460,6 +3535,17 @@ segment_destroy_children (GtkSourceContextEngine *ce, } } +/** + * segment_destroy: + * + * @ce: the engine. + * @context: the segment to destroy. + * + * Recursively frees given segment. It removes the segment + * from ce structure, but it doesn't update parent and + * siblings. segment_remove() is the function that takes + * care of everything. + */ static void segment_destroy (GtkSourceContextEngine *ce, Segment *segment) @@ -3488,6 +3574,11 @@ segment_destroy (GtkSourceContextEngine *ce, #endif } +/** + * container_context_starts_here: + * + * See child_starts_here. + */ static gboolean container_context_starts_here (GtkSourceContextEngine *ce, Segment *state, @@ -3542,6 +3633,11 @@ container_context_starts_here (GtkSourceContextEngine *ce, return TRUE; } +/** + * simple_context_starts_here: + * + * See child_starts_here. + */ static gboolean simple_context_starts_here (GtkSourceContextEngine *ce, Segment *state, @@ -3637,6 +3733,17 @@ child_starts_here (GtkSourceContextEngine *ce, } } +/** + * segment_ends_here: + * + * @state: the segment. + * @line: analyzed line. + * @pos: the position inside @line. + * + * Checks whether given segment ends at pos. Unlike + * child_starts_here it doesn't modify tree, it merely + * calls regex_match() for the end regex. + */ static gboolean segment_ends_here (Segment *state, LineInfo *line, @@ -3652,20 +3759,17 @@ segment_ends_here (Segment *state, } /** - * ancestor_ends_here: + * ancestor_context_ends_here: * - * @state: current state. + * @state: current context. * @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. + * Verifies if some ancestor context ends at the current position. + * This function only checks conetxts and does not modify the tree, + * it's used by ancestor_ends_here(). * - * Return value: %TRUE if an ancestor ends at the given position. + * Return value: the ancestor context that terminates here or NULL. */ static Context * ancestor_context_ends_here (Context *state, @@ -3716,6 +3820,21 @@ ancestor_context_ends_here (Context *state, return terminating_context; } +/** + * ancestor_ends_here: + * + * @state: current state. + * @line: the line to analyze. + * @line_pos: the position inside @line. + * @new_state: where to store the new state. + * + * Verifies if some ancestor context ends at given 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 gboolean ancestor_ends_here (Segment *state, LineInfo *line, @@ -4365,11 +4484,16 @@ get_segment_at_offset (GtkSourceContextEngine *ce, if (offset == ce->priv->root_segment->end_at) return ce->priv->root_segment; +#if 1 + /* if you see this message (often), then something is + * wrong with the hints business, i.e. optimizations + * do not work quite like they should */ if (hint == NULL || hint == ce->priv->root_segment) { static int c; g_print ("searching from root %d\n", ++c); } +#endif result = get_segment_ (hint ? hint : ce->priv->root_segment, offset); @@ -4384,7 +4508,7 @@ get_segment_at_offset (GtkSourceContextEngine *ce, * segment_remove: * * @ce: #GtkSoucreContextEngine. - * @segment: segment remove. + * @segment: segment to remove. * * Removes the segment from syntax tree and frees it. * It correctly updates parent's children list, not @@ -4841,9 +4965,7 @@ erase_segments (GtkSourceContextEngine *ce, * 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). */ +/* XXX it needs to be refactored. */ static void update_syntax (GtkSourceContextEngine *ce, const GtkTextIter *end, @@ -4941,10 +5063,12 @@ update_syntax (GtkSourceContextEngine *ce, erase_segments (ce, line_start_offset, line_end_offset, ce->priv->hint); get_line_info (buffer, &line_start, &line_end, &line); +#ifdef ENABLE_CHECK_TREE { - invalid = get_invalid_segment (ce); - g_assert (!invalid || invalid->start_at >= line_end_offset); + Segment *inv = get_invalid_segment (ce); + g_assert (inv == NULL || inv->start_at >= line_end_offset); } +#endif if (line_start_offset == 0) state = ce->priv->root_segment; @@ -4961,9 +5085,11 @@ update_syntax (GtkSourceContextEngine *ce, state = analyze_line (ce, state, &line); - invalid = get_invalid_segment (ce); #ifdef ENABLE_CHECK_TREE - g_assert (invalid == NULL || invalid->start_at >= line_end_offset); + { + Segment *inv = get_invalid_segment (ce); + g_assert (inv == NULL || inv->start_at >= line_end_offset); + } #endif /* XXX this is wrong */ @@ -5064,6 +5190,7 @@ update_syntax (GtkSourceContextEngine *ce, g_timer_destroy (timer); out: + /* must call context_thaw, so this is the only return point */ context_thaw (ce->priv->root_context); } diff --git a/moo/mooedit/gtksourceview/gtksourcelanguage-private.h b/moo/mooedit/gtksourceview/gtksourcelanguage-private.h index 556ee156..c7af189b 100644 --- a/moo/mooedit/gtksourceview/gtksourcelanguage-private.h +++ b/moo/mooedit/gtksourceview/gtksourcelanguage-private.h @@ -27,6 +27,9 @@ G_BEGIN_DECLS +#define GTK_SOURCE_LANGUAGE_VERSION_1_0 100 +#define GTK_SOURCE_LANGUAGE_VERSION_2_0 200 + struct _GtkSourceLanguagePrivate { gchar *lang_file_name; @@ -42,11 +45,7 @@ struct _GtkSourceLanguagePrivate gint version; gboolean hidden; - GSList *mime_types; - - gchar *line_comment; - gchar *block_comment_start; - gchar *block_comment_end; + GHashTable *properties; GtkSourceLanguagesManager *languages_manager; }; diff --git a/moo/mooedit/gtksourceview/gtksourcelanguage.c b/moo/mooedit/gtksourceview/gtksourcelanguage.c index 5fcd6385..3038f332 100644 --- a/moo/mooedit/gtksourceview/gtksourcelanguage.c +++ b/moo/mooedit/gtksourceview/gtksourcelanguage.c @@ -46,31 +46,6 @@ static void gtk_source_language_finalize (GObject *object); static GtkSourceLanguage *process_language_node (xmlTextReaderPtr reader, const gchar *filename); -/* Signals */ -enum { - LAST_SIGNAL -}; - -// static guint signals[LAST_SIGNAL] = { 0 }; - - -static GSList * -slist_deep_copy (GSList *list) -{ - GSList *l, *copy = NULL; - - for (l = list; l != NULL; l = l->next) - copy = g_slist_prepend (copy, g_strdup (l->data)); - - return g_slist_reverse (copy); -} - -static void -slist_deep_free (GSList *list) -{ - g_slist_foreach (list, (GFunc) g_free, NULL); - g_slist_free (list); -} GtkSourceLanguage * _gtk_source_language_new_from_file (const gchar *filename, @@ -149,6 +124,7 @@ gtk_source_language_init (GtkSourceLanguage *lang) { lang->priv = g_new0 (GtkSourceLanguagePrivate, 1); lang->priv->styles = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + lang->priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } static void @@ -165,11 +141,8 @@ gtk_source_language_finalize (GObject *object) g_free (lang->priv->name); g_free (lang->priv->section); g_free (lang->priv->id); - slist_deep_free (lang->priv->mime_types); + g_hash_table_destroy (lang->priv->properties); g_hash_table_destroy (lang->priv->styles); - g_free (lang->priv->line_comment); - g_free (lang->priv->block_comment_start); - g_free (lang->priv->block_comment_end); g_free (lang->priv); lang->priv = NULL; } @@ -177,6 +150,7 @@ gtk_source_language_finalize (GObject *object) G_OBJECT_CLASS (gtk_source_language_parent_class)->finalize (object); } +#if 0 static GSList * parse_mime_types (xmlTextReaderPtr reader, const char *attr_name) @@ -201,6 +175,7 @@ parse_mime_types (xmlTextReaderPtr reader, return g_slist_reverse (list); } +#endif static gboolean string_to_bool (const gchar *string) @@ -217,90 +192,64 @@ string_to_bool (const gchar *string) g_return_val_if_reached (FALSE); } -static gboolean -get_attribute (xmlTextReaderPtr reader, - const gchar *element, - const gchar *attribute, - gchar **dest) -{ - xmlChar *tmp = xmlTextReaderGetAttribute (reader, BAD_CAST attribute); - - if (tmp == NULL) - { - g_warning ("missing %s attribute in %s element", - attribute, element); - return FALSE; - } - else - { - *dest = g_strdup ((gchar*) tmp); - xmlFree (tmp); - return TRUE; - } -} - static void -process_and_comments (xmlTextReaderPtr reader, - GtkSourceLanguage *language) +process_properties (xmlTextReaderPtr reader, + GtkSourceLanguage *language) { gint ret; - gboolean line_comment_done = FALSE; - gboolean block_comment_done = FALSE; + xmlNodePtr child; + xmlNodePtr node = NULL; - ret = xmlTextReaderRead (reader); - - while (ret == 1) + while (node == NULL && (ret = xmlTextReaderRead (reader)) == 1) { - if (xmlTextReaderNodeType (reader) == 1) + xmlChar *name; + + if (xmlTextReaderNodeType (reader) != 1) + continue; + + name = xmlTextReaderName (reader); + + if (xmlStrcmp (name, BAD_CAST "metadata") != 0) { - xmlChar *name; - - name = xmlTextReaderName (reader); - - if (!xmlStrcmp (name, BAD_CAST "line-comment")) - { - if (line_comment_done) - { - g_warning ("duplicated %s element", name); - ret = 0; - } - else - { - if (!get_attribute (reader, "line-comment", "start", - &language->priv->line_comment)) - ret = 0; - else - line_comment_done = TRUE; - } - } - else if (!xmlStrcmp (name, BAD_CAST "block-comment")) - { - if (block_comment_done) - { - g_warning ("duplicated %s element", name); - ret = 0; - } - else - { - if (!get_attribute (reader, "block-comment", "start", - &language->priv->block_comment_start)) - ret = 0; - else if (!get_attribute (reader, "block-comment", "end", - &language->priv->block_comment_end)) - ret = 0; - else - block_comment_done = TRUE; - } - } - - if (line_comment_done && block_comment_done) - ret = 0; - xmlFree (name); + continue; } - if (ret == 1) - ret = xmlTextReaderRead (reader); + xmlFree (name); + + node = xmlTextReaderExpand (reader); + + if (node == NULL) + return; + } + + if (node == NULL) + return; + + for (child = node->children; child != NULL; child = child->next) + { + xmlChar *name; + xmlChar *content; + + if (child->type != XML_ELEMENT_NODE) + continue; + + if (xmlStrcmp (child->name, BAD_CAST "property") != 0) + { + g_warning ("unknown element %s", (char*) child->name); + continue; + } + + name = xmlGetProp (child, BAD_CAST "name"); + content = xmlNodeGetContent (child); + + if (name != NULL && content != NULL) + g_hash_table_insert (language->priv->properties, + g_strdup ((char*) name), + g_strdup ((char*) content)); + + xmlFree (name); + xmlFree (content); } } @@ -411,10 +360,8 @@ process_language_node (xmlTextReaderPtr reader, const gchar *filename) xmlFree (version); - lang->priv->mime_types = parse_mime_types (reader, "mimetypes"); - if (lang->priv->version == GTK_SOURCE_LANGUAGE_VERSION_2_0) - process_and_comments (reader, lang); + process_properties (reader, lang); return lang; } @@ -492,9 +439,46 @@ gtk_source_language_get_version (GtkSourceLanguage *language) GSList * gtk_source_language_get_mime_types (GtkSourceLanguage *language) { + const gchar *prop; + gchar **mtl; + gint i; + GSList *list = NULL; + g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL); - return slist_deep_copy (language->priv->mime_types); + prop = gtk_source_language_get_property (language, "mimetypes"); + + if (!prop) + return NULL; + + mtl = g_strsplit_set (prop, ";,", 0); + + for (i = 0; mtl[i] != NULL; i++) + /* steal the strings from the array */ + list = g_slist_prepend (list, mtl[i]); + + g_free (mtl); + + return g_slist_reverse (list); +} + +/** + * gtk_source_language_get_property: + * + * @language: a #GtkSourceLanguage. + * @name: property name. + * + * Returns value of property %name if it's set in the lang file + * and NULL otherwise. + **/ +const gchar * +gtk_source_language_get_property (GtkSourceLanguage *language, + const gchar *name) +{ + g_return_val_if_fail (GTK_IS_SOURCE_LANGUAGE (language), NULL); + g_return_val_if_fail (name != NULL, NULL); + + return g_hash_table_lookup (language->priv->properties, name); } /** diff --git a/moo/mooedit/gtksourceview/gtksourcelanguage.h b/moo/mooedit/gtksourceview/gtksourcelanguage.h index 634dd851..e69fd931 100644 --- a/moo/mooedit/gtksourceview/gtksourcelanguage.h +++ b/moo/mooedit/gtksourceview/gtksourcelanguage.h @@ -51,9 +51,6 @@ struct _GtkSourceLanguageClass GObjectClass parent_class; }; -#define GTK_SOURCE_LANGUAGE_VERSION_1_0 100 -#define GTK_SOURCE_LANGUAGE_VERSION_2_0 200 - GType gtk_source_language_get_type (void) G_GNUC_CONST; gchar *gtk_source_language_get_id (GtkSourceLanguage *language); @@ -64,6 +61,8 @@ gint gtk_source_language_get_version (GtkSourceLanguage *language); /* Should free the list (and free each string in it also). */ GSList *gtk_source_language_get_mime_types (GtkSourceLanguage *language); +const gchar *gtk_source_language_get_property (GtkSourceLanguage *language, + const gchar *name); G_END_DECLS diff --git a/moo/mooedit/language-specs/changelog.lang b/moo/mooedit/language-specs/changelog.lang index f4ebd8f9..8092be9a 100644 --- a/moo/mooedit/language-specs/changelog.lang +++ b/moo/mooedit/language-specs/changelog.lang @@ -1,6 +1,9 @@ - + + + + text/x-changelog +