[gnome-builder] xml: add a generic parser for xml and html



commit c4d15a44238dec3f6d26373d9c289cc1d8871efd
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Tue Feb 7 16:02:07 2017 +0100

    xml: add a generic parser for xml and html

 data/style-schemes/builder-dark.xml             |   13 +-
 data/style-schemes/builder.xml                  |   13 +-
 libide/symbols/ide-symbol.h                     |    3 +-
 plugins/symbol-tree/symbol-tree-builder.c       |    8 +-
 plugins/xml-pack/ide-xml-tree-builder-generic.c |  432 +++++++++++++++++++----
 plugins/xml-pack/ide-xml-tree-builder.c         |    3 +-
 plugins/xml-pack/ide-xml-tree-builder.h         |    1 +
 7 files changed, 379 insertions(+), 94 deletions(-)
---
diff --git a/data/style-schemes/builder-dark.xml b/data/style-schemes/builder-dark.xml
index 957aa44..e404703 100644
--- a/data/style-schemes/builder-dark.xml
+++ b/data/style-schemes/builder-dark.xml
@@ -177,12 +177,13 @@
   <style name="xml:tag-match"               background="#rgba(114,159,207,.20)"/>
 
   <!-- Symbol-tree xml-pack coloring -->
-  <style name="symboltree::ui-label"        foreground="#000000" background="#D5E7FC"/>
-  <style name="symboltree::ui-id"           foreground="#000000" background="#D9E7BD"/>
-  <style name="symboltree::ui-style-class"  foreground="#000000" background="#DFCD9B"/>
-  <style name="symboltree::ui-type"         foreground="#000000" background="#F4DAC3"/>
-  <style name="symboltree::ui-parent"       foreground="#000000" background="#DEBECF"/>
-  <style name="symboltree::ui-class"        foreground="#000000" background="#FFEF98"/>
+  <style name="symboltree::label"           foreground="#000000" background="#D5E7FC"/>
+  <style name="symboltree::id"              foreground="#000000" background="#D9E7BD"/>
+  <style name="symboltree::style-class"     foreground="#000000" background="#DFCD9B"/>
+  <style name="symboltree::type"            foreground="#000000" background="#F4DAC3"/>
+  <style name="symboltree::parent"          foreground="#000000" background="#DEBECF"/>
+  <style name="symboltree::class"           foreground="#000000" background="#FFEF98"/>
+  <style name="symboltree::attribute"       foreground="#000000" background="#F0E68C"/>
 
 </style-scheme>
 
diff --git a/data/style-schemes/builder.xml b/data/style-schemes/builder.xml
index d29e847..4f4eead 100644
--- a/data/style-schemes/builder.xml
+++ b/data/style-schemes/builder.xml
@@ -182,11 +182,12 @@
   <style name="sh:variable-definition"      foreground="chameleon3"/>
 
   <!-- Symbol-tree xml-pack coloring -->
-  <style name="symboltree::ui-label"        foreground="#000000" background="#D5E7FC"/>
-  <style name="symboltree::ui-id"           foreground="#000000" background="#D9E7BD"/>
-  <style name="symboltree::ui-style-class"  foreground="#000000" background="#DFCD9B"/>
-  <style name="symboltree::ui-type"         foreground="#000000" background="#F4DAC3"/>
-  <style name="symboltree::ui-parent"       foreground="#000000" background="#DEBECF"/>
-  <style name="symboltree::ui-class"        foreground="#000000" background="#FFEF98"/>
+  <style name="symboltree::label"           foreground="#000000" background="#D5E7FC"/>
+  <style name="symboltree::id"              foreground="#000000" background="#D9E7BD"/>
+  <style name="symboltree::style-class"     foreground="#000000" background="#DFCD9B"/>
+  <style name="symboltree::type"            foreground="#000000" background="#F4DAC3"/>
+  <style name="symboltree::parent"          foreground="#000000" background="#DEBECF"/>
+  <style name="symboltree::class"           foreground="#000000" background="#FFEF98"/>
+  <style name="symboltree::attribute"       foreground="#000000" background="#F0E68C"/>>
 
 </style-scheme>
diff --git a/libide/symbols/ide-symbol.h b/libide/symbols/ide-symbol.h
index be88f06..7e31d92 100644
--- a/libide/symbols/ide-symbol.h
+++ b/libide/symbols/ide-symbol.h
@@ -66,9 +66,10 @@ typedef enum
   IDE_SYMBOL_UI_SUBMENU,
   IDE_SYMBOL_UI_TEMPLATE,
   IDE_SYMBOL_XML_ATTRIBUTE,
-  IDE_SYMBOL_XML_CONTENT,
   IDE_SYMBOL_XML_DECLARATION,
   IDE_SYMBOL_XML_ELEMENT,
+  IDE_SYMBOL_XML_COMMENT,
+  IDE_SYMBOL_XML_CDATA,
 } IdeSymbolKind;
 
 typedef enum
diff --git a/plugins/symbol-tree/symbol-tree-builder.c b/plugins/symbol-tree/symbol-tree-builder.c
index bb17498..b33e56d 100644
--- a/plugins/symbol-tree/symbol-tree-builder.c
+++ b/plugins/symbol-tree/symbol-tree-builder.c
@@ -177,8 +177,12 @@ symbol_tree_builder_build_node (IdeTreeBuilder *builder,
           icon_name = "xml-attribute-symbolic";
           break;
 
-        case IDE_SYMBOL_XML_CONTENT:
-          icon_name = "xml-content-symbolic";
+        case IDE_SYMBOL_XML_CDATA:
+          icon_name = "xml-cdata-symbolic";
+          break;
+
+        case IDE_SYMBOL_XML_COMMENT:
+          icon_name = "xml-comment-symbolic";
           break;
 
         case IDE_SYMBOL_XML_DECLARATION:
diff --git a/plugins/xml-pack/ide-xml-tree-builder-generic.c b/plugins/xml-pack/ide-xml-tree-builder-generic.c
index 211e3a3..98c291c 100644
--- a/plugins/xml-pack/ide-xml-tree-builder-generic.c
+++ b/plugins/xml-pack/ide-xml-tree-builder-generic.c
@@ -17,23 +17,323 @@
  */
 
 #include "ide-xml-stack.h"
+#include "ide-xml-symbol-node.h"
 #include "ide-xml-tree-builder-utils-private.h"
 
 #include "ide-xml-tree-builder-generic.h"
 
-static IdeXmlSymbolNode *
-create_node_from_reader (XmlReader *reader)
+typedef enum _BuildState
 {
-  const gchar *name;
-  GFile *file = NULL;
-  guint line = 0;
-  guint line_offset = 0;
+  BUILD_STATE_NORMAL,
+  BUILD_STATE_WAIT_END_ELEMENT,
+  BUILD_STATE_GET_CONTENT,
+} BuildState;
 
-  name = xml_reader_get_name (reader);
+typedef struct _ParserState
+{
+  IdeXmlTreeBuilder *self;
+  IdeXmlSax         *parser;
+  IdeXmlStack       *stack;
+  GFile             *file;
+  IdeXmlAnalysis    *analysis;
+  GPtrArray         *diagnostics_array;
+  IdeXmlSymbolNode  *root_node;
+  IdeXmlSymbolNode  *parent_node;
+  IdeXmlSymbolNode  *current_node;
+  BuildState         build_state;
+  gint               current_depth;
+} ParserState;
 
-  return ide_xml_symbol_node_new (name, NULL, NULL,
-                                  IDE_SYMBOL_UI_OBJECT,
-                                  file, line, line_offset);
+static void
+parser_state_free (ParserState *state)
+{
+  g_clear_pointer (&state->analysis, ide_xml_analysis_unref);
+  g_clear_pointer (&state->diagnostics_array, g_ptr_array_unref);
+  g_clear_object (&state->stack);
+  g_clear_object (&state->file);
+  g_clear_object (&state->parser);
+  g_clear_object (&state->root_node);
+}
+
+static void
+state_processing (ParserState           *state,
+                  const gchar           *element_name,
+                  IdeXmlSymbolNode      *node,
+                  IdeXmlSaxCallbackType  callback_type,
+                  gboolean               is_internal)
+{
+  IdeXmlSymbolNode *parent_node;
+  IdeXmlSymbolNode *popped_node G_GNUC_UNUSED;
+  g_autofree gchar *popped_element_name = NULL;
+  gint line;
+  gint line_offset;
+  gint depth;
+
+  g_assert (IDE_IS_XML_SYMBOL_NODE (node) || node == NULL);
+
+  if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_CHAR)
+    {
+      ide_xml_symbol_node_set_value (state->current_node, element_name);
+      return;
+    }
+
+  depth = ide_xml_sax_get_depth (state->parser);
+
+  if (node == NULL)
+    {
+      if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT)
+        {
+          /* TODO: compare current with popped */
+          if (ide_xml_stack_is_empty (state->stack))
+            {
+              g_warning ("Xml nodes stack empty\n");
+              return;
+            }
+
+          popped_node = ide_xml_stack_pop (state->stack, &popped_element_name, &parent_node, &depth);
+          state->parent_node = parent_node;
+          g_assert (state->parent_node != NULL);
+        }
+
+      state->current_depth = depth;
+      state->current_node = NULL;
+      return;
+    }
+
+  ide_xml_sax_get_position (state->parser, &line, &line_offset);
+  ide_xml_symbol_node_set_location (node, g_object_ref (state->file), line, line_offset);
+
+  /* TODO: take end elements into account and use:
+   * || ABS (depth - current_depth) > 1
+   */
+  if (depth < 0)
+    {
+      g_warning ("Wrong xml element depth, current:%i new:%i\n", state->current_depth, depth);
+      return;
+    }
+
+  if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_START_ELEMENT)
+    {
+      ide_xml_stack_push (state->stack, element_name, node, state->parent_node, depth);
+      if (is_internal)
+        ide_xml_symbol_node_take_internal_child (state->parent_node, node);
+      else
+        ide_xml_symbol_node_take_child (state->parent_node, node);
+
+      state->parent_node = node;
+    }
+  else if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT)
+    {
+      /* TODO: compare current with popped */
+      if (ide_xml_stack_is_empty (state->stack))
+        {
+          g_warning ("Xml nodes stack empty\n");
+          return;
+        }
+
+      popped_node = ide_xml_stack_pop (state->stack, &popped_element_name, &parent_node, &depth);
+      state->parent_node = parent_node;
+      g_assert (state->parent_node != NULL);
+    }
+  else
+    {
+      ide_xml_symbol_node_take_child (state->parent_node, node);
+    }
+
+  state->current_depth = depth;
+  state->current_node = node;
+}
+
+static gchar *
+collect_attributes (IdeXmlTreeBuilder  *self,
+                    const gchar       **attributes)
+{
+  GString *string;
+  gchar *value;
+  const gchar **l = attributes;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  if (attributes == NULL)
+    return NULL;
+
+  string = g_string_new (NULL);
+  while (l [0] != NULL)
+    {
+      value = ide_xml_tree_builder_get_color_tag (self, l [0], COLOR_TAG_ATTRIBUTE, TRUE, TRUE, TRUE);
+      g_string_append (string, value);
+      g_free (value);
+      g_string_append (string, l [1]);
+
+      l += 2;
+    }
+
+  return g_string_free (string, FALSE);
+}
+
+static void
+start_element_sax_cb (ParserState    *state,
+                      const xmlChar  *name,
+                      const xmlChar **attributes)
+{
+  IdeXmlTreeBuilder *self = (IdeXmlTreeBuilder *)state->self;
+  IdeXmlSymbolNode *node = NULL;
+  g_autofree gchar *attr = NULL;
+  g_autofree gchar *label = NULL;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  attr = collect_attributes (self, (const gchar **)attributes);
+  label = g_strconcat ((const gchar *)name, attr, NULL);
+
+  node = ide_xml_symbol_node_new (label, NULL, NULL, IDE_SYMBOL_XML_ELEMENT, NULL, 0, 0);
+  g_object_set (node, "use-markup", TRUE, NULL);
+
+  state_processing (state, (const gchar *)name, node, IDE_XML_SAX_CALLBACK_TYPE_START_ELEMENT, FALSE);
+}
+
+static void
+comment_sax_cb (ParserState   *state,
+                const xmlChar *name)
+{
+  IdeXmlSymbolNode *node = NULL;
+  g_autofree gchar *strip_name = NULL;
+
+  strip_name = g_strstrip (g_strdup ((const gchar *)name));
+  node = ide_xml_symbol_node_new (strip_name, NULL, NULL, IDE_SYMBOL_XML_COMMENT, NULL, 0, 0);
+  state_processing (state, "comment", node, IDE_XML_SAX_CALLBACK_TYPE_COMMENT, FALSE);
+}
+
+static void
+cdata_sax_cb (ParserState   *state,
+              const xmlChar *value,
+              gint           len)
+{
+  IdeXmlSymbolNode *node = NULL;
+
+  node = ide_xml_symbol_node_new ("cdata", NULL, NULL, IDE_SYMBOL_XML_CDATA, NULL, 0, 0);
+  state_processing (state, "cdata", node, IDE_XML_SAX_CALLBACK_TYPE_CDATA, FALSE);
+}
+
+static void
+end_element_sax_cb (ParserState    *state,
+                    const xmlChar  *name)
+{
+  IdeXmlTreeBuilder *self = (IdeXmlTreeBuilder *)state->self;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  state_processing (state, (const gchar *)name, NULL, IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT, FALSE);
+}
+
+static IdeDiagnostic *
+create_diagnostic (ParserState            *state,
+                   const gchar            *msg,
+                   IdeDiagnosticSeverity   severity)
+{
+  IdeContext *context;
+  IdeDiagnostic *diagnostic;
+  g_autoptr(IdeSourceLocation) loc = NULL;
+  g_autoptr(IdeFile) ifile = NULL;
+  gint line;
+  gint line_offset;
+
+  context = ide_object_get_context (IDE_OBJECT (state->self));
+
+  ide_xml_sax_get_position (state->parser, &line, &line_offset);
+  ifile = ide_file_new (context, state->file);
+  loc = ide_source_location_new (ifile,
+                                 line - 1,
+                                 line_offset - 1,
+                                 0);
+
+  diagnostic = ide_diagnostic_new (severity, msg, loc);
+
+  return diagnostic;
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+static void
+warning_sax_cb (ParserState    *state,
+                const xmlChar  *name,
+                ...)
+{
+  IdeXmlTreeBuilder *self = (IdeXmlTreeBuilder *)state->self;
+  IdeDiagnostic *diagnostic;
+  g_autofree gchar *msg = NULL;
+  va_list var_args;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  va_start (var_args, name);
+  msg = g_strdup_vprintf ((const gchar *)name, var_args);
+  va_end (var_args);
+
+  diagnostic = create_diagnostic (state, msg, IDE_DIAGNOSTIC_WARNING);
+  g_ptr_array_add (state->diagnostics_array, diagnostic);
+}
+
+static void
+error_sax_cb (ParserState    *state,
+              const xmlChar  *name,
+              ...)
+{
+  IdeXmlTreeBuilder *self = (IdeXmlTreeBuilder *)state->self;
+  IdeDiagnostic *diagnostic;
+  g_autofree gchar *msg = NULL;
+  va_list var_args;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  va_start (var_args, name);
+  msg = g_strdup_vprintf ((const gchar *)name, var_args);
+  va_end (var_args);
+
+  diagnostic = create_diagnostic (state, msg, IDE_DIAGNOSTIC_ERROR);
+  g_ptr_array_add (state->diagnostics_array, diagnostic);
+}
+
+static void
+fatal_error_sax_cb (ParserState    *state,
+                    const xmlChar  *name,
+                    ...)
+{
+  IdeXmlTreeBuilder *self = (IdeXmlTreeBuilder *)state->self;
+  IdeDiagnostic *diagnostic;
+  g_autofree gchar *msg = NULL;
+  va_list var_args;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  va_start (var_args, name);
+  msg = g_strdup_vprintf ((const gchar *)name, var_args);
+  va_end (var_args);
+
+  diagnostic = create_diagnostic (state, msg, IDE_DIAGNOSTIC_FATAL);
+  g_ptr_array_add (state->diagnostics_array, diagnostic);
+}
+
+#pragma GCC diagnostic pop
+
+static void
+characters_sax_cb (ParserState    *state,
+                   const xmlChar  *name,
+                   gint            len)
+{
+  IdeXmlTreeBuilder *self = (IdeXmlTreeBuilder *)state->self;
+  g_autofree gchar *element_value = NULL;
+
+  g_assert (IDE_IS_XML_TREE_BUILDER (self));
+
+  if (state->build_state != BUILD_STATE_GET_CONTENT)
+    return;
+
+  element_value = g_strndup ((gchar *)name, len);
+  state->build_state = BUILD_STATE_NORMAL;
+
+  state_processing (state, element_value, NULL, IDE_XML_SAX_CALLBACK_TYPE_CHAR, FALSE);
 }
 
 IdeXmlAnalysis *
@@ -41,75 +341,51 @@ ide_xml_tree_builder_generic_create (IdeXmlTreeBuilder *self,
                                      IdeXmlSax         *parser,
                                      GFile             *file,
                                      const gchar       *data,
-                                     gsize              size)
+                                     gsize              length)
 {
-  IdeXmlStack *stack;
-  IdeXmlAnalysis *analysis = NULL;
-  IdeXmlSymbolNode *parent_node;
-  IdeXmlSymbolNode *current_node;
-  IdeXmlSymbolNode *previous_node = NULL;
-  xmlReaderTypes type;
-  gint depth = 0;
-  gint current_depth = 0;
-  gboolean is_empty;
-
-  /* g_assert (XML_IS_READER (reader)); */
-
-  /* stack = stack_new (); */
-
-  /* parent_node = root_node = ide_xml_symbol_node_new ("root", IDE_SYMBOL_NONE, */
-  /*                                                    NULL, 0, 0); */
-  /* stack_push (stack, parent_node); */
-
-  /* while (xml_reader_read (reader)) */
-  /*   { */
-  /*     type = xml_reader_get_node_type (reader); */
-  /*     if ( type == XML_READER_TYPE_ELEMENT) */
-  /*       { */
-  /*         current_node = create_node_from_reader (reader); */
-  /*         depth = xml_reader_get_depth (reader); */
-  /*         is_empty = xml_reader_is_empty_element (reader); */
-  /*         if (depth < 0) */
-  /*           { */
-  /*             g_warning ("Wrong xml element depth, current:%i new:%i\n", current_depth, depth); */
-  /*             break; */
-  /*           } */
-
-  /*         if (depth > current_depth) */
-  /*           { */
-  /*             ++current_depth; */
-  /*             stack_push (stack, parent_node); */
-
-  /*             g_assert (previous_node != NULL); */
-  /*             parent_node = previous_node; */
-  /*             ide_xml_symbol_node_take_child (parent_node, current_node); */
-  /*           } */
-  /*         else if (depth < current_depth) */
-  /*           { */
-  /*             --current_depth; */
-  /*             parent_node = stack_pop (stack); */
-  /*             if (parent_node == NULL) */
-  /*               { */
-  /*                 g_warning ("Xml nodes stack empty\n"); */
-  /*                 break; */
-  /*               } */
-
-  /*             g_assert (parent_node != NULL); */
-  /*             ide_xml_symbol_node_take_child (parent_node, current_node); */
-  /*           } */
-  /*         else */
-  /*           { */
-  /*             ide_xml_symbol_node_take_child (parent_node, current_node); */
-  /*           } */
-
-  /*         previous_node = current_node; */
-  /*         print_node (current_node, depth); */
-  /*       } */
-  /*   } */
-
-  /* printf ("stack size:%li\n", stack_get_size (stack)); */
-
-  /* stack_destroy (stack); */
+  ParserState *state;
+  IdeXmlAnalysis *analysis;
+  g_autoptr(IdeDiagnostics) diagnostics = NULL;
+  g_autofree gchar *uri = NULL;
+
+  g_return_val_if_fail (IDE_IS_XML_SAX (parser), NULL);
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+  g_return_val_if_fail (data != NULL, NULL);
+  g_return_val_if_fail (length > 0, NULL);
+
+  state = g_slice_new0 (ParserState);
+  state->self = self;
+  state->parser = g_object_ref (parser);
+  state->stack = ide_xml_stack_new ();
+  state->file = g_object_ref (file);
+  state->diagnostics_array = g_ptr_array_new_with_free_func ((GDestroyNotify)ide_diagnostic_unref);
+  state->build_state = BUILD_STATE_NORMAL;
+
+  ide_xml_sax_clear (parser);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_START_ELEMENT, start_element_sax_cb);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT, end_element_sax_cb);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_COMMENT, comment_sax_cb);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_CDATA, cdata_sax_cb);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_CHAR, characters_sax_cb);
+
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_WARNING, warning_sax_cb);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_ERROR, error_sax_cb);
+  ide_xml_sax_set_callback (parser, IDE_XML_SAX_CALLBACK_TYPE_FATAL_ERROR, fatal_error_sax_cb);
+
+  state->analysis = ide_xml_analysis_new (-1);
+  state->root_node = ide_xml_symbol_node_new ("root", NULL, "root", IDE_SYMBOL_NONE, NULL, 0, 0);
+  ide_xml_analysis_set_root_node (state->analysis, state->root_node);
+
+  state->parent_node = state->root_node;
+  ide_xml_stack_push (state->stack, "root", state->root_node, NULL, 0);
+
+  uri = g_file_get_uri (file);
+  ide_xml_sax_parse (parser, data, length, uri, state);
+
+  analysis = g_steal_pointer (&state->analysis);
+  diagnostics = ide_diagnostics_new (g_steal_pointer (&state->diagnostics_array));
+  ide_xml_analysis_set_diagnostics (analysis, diagnostics);
 
+  parser_state_free (state);
   return analysis;
 }
diff --git a/plugins/xml-pack/ide-xml-tree-builder.c b/plugins/xml-pack/ide-xml-tree-builder.c
index 78d90d5..50cd1a8 100644
--- a/plugins/xml-pack/ide-xml-tree-builder.c
+++ b/plugins/xml-pack/ide-xml-tree-builder.c
@@ -52,6 +52,7 @@ static ColorTag default_color_tags [] =
   { "type",        "#000000", "#F4DAC3" }, // COLOR_TAG_TYPE
   { "parent",      "#000000", "#DEBECF" }, // COLOR_TAG_PARENT
   { "class",       "#000000", "#FFEF98" }, // COLOR_TAG_CLASS
+  { "attribute",   "#000000", "#F0E68C" }, // COLOR_TAG_ATTRIBUTE
   { NULL },
 };
 
@@ -279,7 +280,7 @@ init_color_tags (IdeXmlTreeBuilder *self)
       tag_set = FALSE;
       if (scheme != NULL)
         {
-          tag_name = g_strconcat ("symboltree::ui-", tag_ptr->name, NULL);
+          tag_name = g_strconcat ("symboltree::", tag_ptr->name, NULL);
           if (NULL != (style = gtk_source_style_scheme_get_style (scheme, tag_name)))
             {
               g_object_get (style, "foreground", &foreground, NULL);
diff --git a/plugins/xml-pack/ide-xml-tree-builder.h b/plugins/xml-pack/ide-xml-tree-builder.h
index d903dab..7bc6a33 100644
--- a/plugins/xml-pack/ide-xml-tree-builder.h
+++ b/plugins/xml-pack/ide-xml-tree-builder.h
@@ -39,6 +39,7 @@ typedef enum _ColorTagId
   COLOR_TAG_TYPE,
   COLOR_TAG_PARENT,
   COLOR_TAG_CLASS,
+  COLOR_TAG_ATTRIBUTE,
 } ColorTagId;
 
 IdeXmlTreeBuilder   *ide_xml_tree_builder_new                    (void);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]