[gnome-builder] xml: parser rework to use SAX and new stack



commit fa51236c2f740ea0d8e60be241789f0bfa53dcda
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Sun Jan 29 16:13:53 2017 +0100

    xml: parser rework to use SAX and new stack

 plugins/xml-pack/Makefile.am                       |    6 +
 plugins/xml-pack/ide-xml-symbol-node.c             |  122 ++++++---
 plugins/xml-pack/ide-xml-symbol-node.h             |   15 +-
 plugins/xml-pack/ide-xml-tree-builder-generic.c    |  114 ++++++++
 plugins/xml-pack/ide-xml-tree-builder-generic.h    |   37 +++
 plugins/xml-pack/ide-xml-tree-builder-ui.c         |  294 ++++++++++++++++++++
 plugins/xml-pack/ide-xml-tree-builder-ui.h         |   37 +++
 .../xml-pack/ide-xml-tree-builder-utils-private.h  |   36 +++
 plugins/xml-pack/ide-xml-tree-builder-utils.c      |   69 +++++
 plugins/xml-pack/ide-xml-tree-builder.c            |  247 +----------------
 10 files changed, 699 insertions(+), 278 deletions(-)
---
diff --git a/plugins/xml-pack/Makefile.am b/plugins/xml-pack/Makefile.am
index f05f02b..78e14f9 100644
--- a/plugins/xml-pack/Makefile.am
+++ b/plugins/xml-pack/Makefile.am
@@ -25,6 +25,12 @@ libxml_pack_plugin_la_SOURCES = \
        ide-xml-symbol-tree.h \
        ide-xml-tree-builder.c \
        ide-xml-tree-builder.h \
+       ide-xml-tree-builder-generic.c \
+       ide-xml-tree-builder-generic.h \
+       ide-xml-tree-builder-ui.c \
+       ide-xml-tree-builder-ui.h \
+       ide-xml-tree-builder-utils.c \
+       ide-xml-tree-builder-utils-private.h \
        ide-xml.c \
        ide-xml.h \
        xml-pack-plugin.c \
diff --git a/plugins/xml-pack/ide-xml-symbol-node.c b/plugins/xml-pack/ide-xml-symbol-node.c
index c1005a9..49a9305 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.c
+++ b/plugins/xml-pack/ide-xml-symbol-node.c
@@ -25,38 +25,16 @@ struct _IdeXmlSymbolNode
 {
   IdeSymbolNode             parent_instance;
   GPtrArray                *children;
+  gchar                    *element_name;
   GFile                    *file;
-  guint                     line;
-  guint                     line_offset;
+  gint                      line;
+  gint                      line_offset;
   gint64                    serial;
 };
 
 G_DEFINE_TYPE (IdeXmlSymbolNode, ide_xml_symbol_node, IDE_TYPE_SYMBOL_NODE)
 
 static void
-ide_xml_symbol_node_get_location_cb (GObject      *object,
-                                     GAsyncResult *result,
-                                     gpointer      user_data)
-{
-  IdeXmlSymbolResolver *resolver = (IdeXmlSymbolResolver *)object;
-  g_autoptr(IdeSourceLocation) location = NULL;
-  g_autoptr(GTask) task = user_data;
-  g_autoptr(GError) error = NULL;
-
-  g_assert (IDE_IS_XML_SYMBOL_RESOLVER (resolver));
-  g_assert (G_IS_TASK (task));
-
-  //location = ide_xml_symbol_resolver_get_location_finish (resolver, result, &error);
-
-  if (location == NULL)
-    g_task_return_error (task, g_steal_pointer (&error));
-  else
-    g_task_return_pointer (task,
-                           g_steal_pointer (&location),
-                           (GDestroyNotify)ide_source_location_unref);
-}
-
-static void
 ide_xml_symbol_node_get_location_async (IdeSymbolNode       *node,
                                         GCancellable        *cancellable,
                                         GAsyncReadyCallback  callback,
@@ -64,18 +42,28 @@ ide_xml_symbol_node_get_location_async (IdeSymbolNode       *node,
 {
   IdeXmlSymbolNode *self = (IdeXmlSymbolNode *)node;
   g_autoptr(GTask) task = NULL;
+  IdeContext *context;
+  IdeFile *ifile;
+  IdeSourceLocation *ret;
 
   g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (self));
+  g_return_if_fail (G_IS_FILE (self->file));
 
   task = g_task_new (self, cancellable, callback, user_data);
   g_task_set_source_tag (task, ide_xml_symbol_node_get_location_async);
 
-  /* ide_xml_symbol_resolver_get_location_async (self->resolver, */
-  /*                                             self->index, */
-  /*                                             self->entry, */
-  /*                                             NULL, */
-  /*                                             ide_xml_symbol_node_get_location_cb, */
-  /*                                             g_steal_pointer (&task)); */
+  context = ide_object_get_context (IDE_OBJECT (self));
+  ifile = g_object_new (IDE_TYPE_FILE,
+                        "file", self->file,
+                        "context", context,
+                        NULL);
+
+  /* TODO: libxml2 give us the end of a tag, we need to walk back
+   * in the buffer to get the start
+   */
+  ret = ide_source_location_new (ifile, self->line - 1, self->line_offset - 1, 0);
+
+  g_task_return_pointer (task, ret, (GDestroyNotify)ide_source_location_unref);
 }
 
 static IdeSourceLocation *
@@ -95,8 +83,7 @@ ide_xml_symbol_node_finalize (GObject *object)
   IdeXmlSymbolNode *self = (IdeXmlSymbolNode *)object;
 
   g_clear_pointer (&self->children, g_ptr_array_unref);
-  /* self->entry = NULL; */
-  /* g_clear_object (&self->index); */
+  g_free (self->element_name);
 
   G_OBJECT_CLASS (ide_xml_symbol_node_parent_class)->finalize (object);
 }
@@ -120,16 +107,17 @@ ide_xml_symbol_node_init (IdeXmlSymbolNode *self)
 
 IdeXmlSymbolNode *
 ide_xml_symbol_node_new (const gchar            *name,
+                         const gchar            *element_name,
                          IdeSymbolKind           kind,
                          GFile                  *file,
-                         guint                   line,
-                         guint                   line_offset)
+                         gint                    line,
+                         gint                    line_offset)
 {
   IdeXmlSymbolNode *self;
   IdeSymbolFlags flags = IDE_SYMBOL_FLAGS_NONE;
 
   g_assert (!ide_str_empty0 (name));
-  //g_assert (G_IS_FILE (file));
+  g_assert (G_IS_FILE (file)|| file == NULL);
 
   self = g_object_new (IDE_TYPE_XML_SYMBOL_NODE,
                        "name", name,
@@ -137,7 +125,14 @@ ide_xml_symbol_node_new (const gchar            *name,
                        "flags", flags,
                        NULL);
 
-  self->file = file;
+  if (ide_str_empty0 (element_name))
+    self->element_name = g_strdup ("unknow");
+  else
+    self->element_name = g_strdup (element_name);
+
+  if (file != NULL)
+    self->file = g_object_ref (file);
+
   self->line = line;
   self->line_offset = line_offset;
 
@@ -173,6 +168,7 @@ ide_xml_symbol_node_take_child (IdeXmlSymbolNode *self,
 
   if (self->children == NULL)
     self->children = g_ptr_array_new_with_free_func (g_object_unref);
+
   g_ptr_array_add (self->children, child);
 }
 
@@ -183,3 +179,55 @@ ide_xml_symbol_node_get_serial (IdeXmlSymbolNode *self)
 
   return self->serial;
 }
+
+void
+ide_xml_symbol_node_set_location (IdeXmlSymbolNode *self,
+                                  GFile            *file,
+                                  gint              line,
+                                  gint              line_offset)
+{
+  g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (self));
+  g_return_if_fail (G_IS_FILE (file) || file == NULL);
+
+  g_clear_object (&self->file);
+  if (file != NULL)
+    self->file = g_object_ref (file);
+
+  self->line = line;
+  self->line_offset = line_offset;
+}
+
+GFile *
+ide_xml_symbol_node_get_location (IdeXmlSymbolNode *self,
+                                  gint             *line,
+                                  gint             *line_offset)
+{
+  g_return_val_if_fail (IDE_IS_XML_SYMBOL_NODE (self), NULL);
+
+  if (line != NULL)
+    *line = self->line;
+
+  if (line_offset != NULL)
+    *line_offset = self->line_offset;
+
+  return self->file;
+}
+
+const gchar *
+ide_xml_symbol_node_get_element_name (IdeXmlSymbolNode *self)
+{
+  g_return_val_if_fail (IDE_IS_XML_SYMBOL_NODE (self), NULL);
+
+  return self->element_name;
+}
+
+void
+ide_xml_symbol_node_set_element_name (IdeXmlSymbolNode *self,
+                                      const gchar      *element_name)
+{
+  g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (self));
+  g_return_if_fail (!ide_str_empty0 (element_name));
+
+  g_free (self->element_name);
+  self->element_name = g_strdup (element_name);
+}
diff --git a/plugins/xml-pack/ide-xml-symbol-node.h b/plugins/xml-pack/ide-xml-symbol-node.h
index 613beba..82bda7f 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.h
+++ b/plugins/xml-pack/ide-xml-symbol-node.h
@@ -30,16 +30,27 @@ G_BEGIN_DECLS
 G_DECLARE_FINAL_TYPE (IdeXmlSymbolNode, ide_xml_symbol_node, IDE, XML_SYMBOL_NODE, IdeSymbolNode)
 
 IdeXmlSymbolNode         *ide_xml_symbol_node_new              (const gchar            *name,
+                                                                const gchar            *element_name,
                                                                 IdeSymbolKind           kind,
                                                                 GFile                  *file,
-                                                                guint                   line,
-                                                                guint                   line_offset);
+                                                                gint                    line,
+                                                                gint                    line_offset);
 void                      ide_xml_symbol_node_take_child       (IdeXmlSymbolNode       *self,
                                                                 IdeXmlSymbolNode       *child);
+const gchar              *ide_xml_symbol_node_get_element_name (IdeXmlSymbolNode       *self);
+GFile *                   ide_xml_symbol_node_get_location     (IdeXmlSymbolNode       *self,
+                                                                gint                   *line,
+                                                                gint                   *line_offset);
 guint                     ide_xml_symbol_node_get_n_children   (IdeXmlSymbolNode       *self);
 IdeSymbolNode            *ide_xml_symbol_node_get_nth_child    (IdeXmlSymbolNode       *self,
                                                                 guint                   nth_child);
 gint64                    ide_xml_symbol_node_get_serial       (IdeXmlSymbolNode       *self);
+void                      ide_xml_symbol_node_set_location     (IdeXmlSymbolNode       *self,
+                                                                GFile                  *file,
+                                                                gint                    line,
+                                                                gint                    line_offset);
+void                      ide_xml_symbol_node_set_element_name (IdeXmlSymbolNode       *self,
+                                                                const gchar            *element_name);
 
 G_END_DECLS
 
diff --git a/plugins/xml-pack/ide-xml-tree-builder-generic.c b/plugins/xml-pack/ide-xml-tree-builder-generic.c
new file mode 100644
index 0000000..11376ce
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-tree-builder-generic.c
@@ -0,0 +1,114 @@
+/* ide-xml-tree-builder-generic.c
+ *
+ * Copyright (C) 2017 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ide-xml-stack.h"
+#include "ide-xml-tree-builder-utils-private.h"
+
+#include "ide-xml-tree-builder-generic.h"
+
+static IdeXmlSymbolNode *
+create_node_from_reader (XmlReader *reader)
+{
+  const gchar *name;
+  GFile *file = NULL;
+  guint line = 0;
+  guint line_offset = 0;
+
+  name = xml_reader_get_name (reader);
+
+  return ide_xml_symbol_node_new (name, NULL,
+                                  IDE_SYMBOL_UI_OBJECT,
+                                  file, line, line_offset);
+}
+
+IdeXmlSymbolNode *
+ide_xml_tree_builder_generic_create (IdeXmlSax   *parser,
+                                     GFile       *file,
+                                     const gchar *data,
+                                     gsize        size)
+{
+  IdeXmlStack *stack;
+  IdeXmlSymbolNode *root_node;
+  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); */
+
+  return root_node;
+}
diff --git a/plugins/xml-pack/ide-xml-tree-builder-generic.h b/plugins/xml-pack/ide-xml-tree-builder-generic.h
new file mode 100644
index 0000000..b490fb4
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-tree-builder-generic.h
@@ -0,0 +1,37 @@
+/* ide-xml-tree-builder-generic.h
+ *
+ * Copyright (C) 2017 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_XML_TREE_BUILDER_GENERIC_H
+#define IDE_XML_TREE_BUILDER_GENERIC_H
+
+#include <glib.h>
+
+#include "ide-xml-sax.h"
+#include "ide-xml-symbol-node.h"
+#include "xml-reader.h"
+
+G_BEGIN_DECLS
+
+IdeXmlSymbolNode *ide_xml_tree_builder_generic_create (IdeXmlSax   *parser,
+                                                       GFile       *file,
+                                                       const gchar *data,
+                                                       gsize        size);
+
+G_END_DECLS
+
+#endif /* IDE_XML_TREE_BUILDER_GENERIC_H */
diff --git a/plugins/xml-pack/ide-xml-tree-builder-ui.c b/plugins/xml-pack/ide-xml-tree-builder-ui.c
new file mode 100644
index 0000000..a81f29d
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-tree-builder-ui.c
@@ -0,0 +1,294 @@
+/* ide-xml-tree-builder-ui.c
+ *
+ * Copyright (C) 2017 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ide-xml-stack.h"
+#include "ide-xml-symbol-node.h"
+#include "ide-xml-tree-builder-utils-private.h"
+
+#include "ide-xml-tree-builder-ui.h"
+
+typedef struct _ParserState
+{
+  IdeXmlSax        *parser;
+  IdeXmlStack      *stack;
+  GFile            *file;
+  IdeXmlSymbolNode *root_node;
+  IdeXmlSymbolNode *parent_node;
+  IdeXmlSymbolNode *current_node;
+  gint              current_depth;
+} ParserState;
+
+static void
+parser_state_free (ParserState *state)
+{
+  g_clear_object (&state->stack);
+  g_clear_object (&state->file);
+  g_clear_object (&state->parser);
+}
+
+static void
+state_processing (ParserState           *state,
+                  const gchar           *element_name,
+                  IdeXmlSymbolNode      *node,
+                  IdeXmlSaxCallbackType  callback_type)
+{
+  IdeXmlSymbolNode *parent_node;
+  IdeXmlSymbolNode *popped_node;
+  g_autofree gchar *popped_element_name = NULL;
+  gint line;
+  gint line_offset;
+  gint depth;
+
+  depth = ide_xml_sax_get_depth (state->parser);
+  printf ("[name:%s depth:%i] ", element_name, depth);
+
+  if (node == NULL)
+    {
+      if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_START_ELEMENT)
+        {
+          ide_xml_stack_push (state->stack, element_name, NULL, state->parent_node, depth);
+
+          printf ("no node PUSH %i->%i\n", state->current_depth, depth);
+        }
+      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);
+
+          printf ("no node POP %i->%i name:%s parent:%p\n",
+                  state->current_depth, depth, popped_element_name, state->parent_node);
+        }
+
+      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);
+      ide_xml_symbol_node_take_child (state->parent_node, node);
+
+      printf ("PUSH %i->%i current:%p parent:%p\n",
+              state->current_depth, depth, node, state->parent_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);
+
+      printf ("POP %i->%i name:%s parent node:%p\n",
+              state->current_depth, depth, popped_element_name, parent_node);
+    }
+  else
+    {
+      printf ("---- %i->%i\n", state->current_depth, depth);
+      ide_xml_symbol_node_take_child (state->parent_node, node);
+    }
+
+  state->current_depth = depth;
+  state->current_node = node;
+  print_node (node, depth);
+}
+
+static const gchar *
+get_attribute (const guchar **list,
+               const gchar   *name,
+               const gchar   *replacement)
+{
+  const gchar *value = NULL;
+
+  value = list_get_attribute (list, name);
+  return ide_str_empty0 (value) ? ((replacement != NULL) ? replacement : NULL) : value;
+}
+
+static void
+start_element_sax_cb (ParserState    *state,
+                      const xmlChar  *name,
+                      const xmlChar **atttributes)
+{
+  g_autoptr (GString) string = NULL;
+  const gchar *value = NULL;
+  IdeXmlSymbolNode *node = NULL;
+
+  string = g_string_new (NULL);
+
+  if (ide_str_equal0 (name, "child"))
+    {
+      g_string_append (string, "child");
+
+      if (NULL != (value = get_attribute (atttributes, "type", NULL)))
+        {
+          g_string_append (string, " type: ");
+          g_string_append (string, value);
+        }
+
+      if (NULL != (value = get_attribute (atttributes, "internal-child", NULL)))
+        {
+          g_string_append (string, " internal: ");
+          g_string_append (string, value);
+        }
+
+      node = ide_xml_symbol_node_new (string->str, "child",
+                                      IDE_SYMBOL_UI_CHILD, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "object"))
+    {
+      value = get_attribute (atttributes, "class", "?");
+      g_string_append (string, value);
+
+      if (NULL != (value = list_get_attribute (atttributes, "id")))
+        {
+          g_string_append (string, " id: ");
+          g_string_append (string, value);
+        }
+
+      node = ide_xml_symbol_node_new (string->str, "object",
+                                      IDE_SYMBOL_UI_OBJECT, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "template"))
+    {
+      value = get_attribute (atttributes, "class", "?");
+      g_string_append (string, value);
+
+      value = get_attribute (atttributes, "parent", "?");
+      g_string_append (string, " parent: ");
+      g_string_append (string, value);
+
+      node = ide_xml_symbol_node_new (string->str, (const gchar *)name,
+                                      IDE_SYMBOL_UI_TEMPLATE, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "packing"))
+    {
+      node = ide_xml_symbol_node_new ("packing", "packing",
+                                      IDE_SYMBOL_UI_PACKING, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "style"))
+    {
+      /* TODO: collect style classes names */
+      node = ide_xml_symbol_node_new ("style", "style",
+                                      IDE_SYMBOL_UI_STYLE, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "menu"))
+    {
+      value = get_attribute (atttributes, "id", "?");
+      g_string_append (string, value);
+
+      node = ide_xml_symbol_node_new (string->str, "menu",
+                                      IDE_SYMBOL_UI_MENU, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "submenu"))
+    {
+      /* TODO: show content of attribute name="label" */
+      value = get_attribute (atttributes, "id", "?");
+      g_string_append (string, value);
+
+      node = ide_xml_symbol_node_new (string->str, "submenu",
+                                      IDE_SYMBOL_UI_SUBMENU, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "section"))
+    {
+      value = get_attribute (atttributes, "id", "?");
+      g_string_append (string, value);
+
+      node = ide_xml_symbol_node_new (string->str, "section",
+                                      IDE_SYMBOL_UI_SECTION, NULL, 0, 0);
+    }
+  else if (ide_str_equal0 (name, "item"))
+    {
+      /* TODO: show content of attribute name="label" */
+      node = ide_xml_symbol_node_new ("item", "item",
+                                      IDE_SYMBOL_UI_ITEM, NULL, 0, 0);
+    }
+
+  state_processing (state, (const gchar *)name, node, IDE_XML_SAX_CALLBACK_TYPE_START_ELEMENT);
+}
+
+static void
+end_element_sax_cb (ParserState    *state,
+                    const xmlChar  *name)
+{
+  printf ("end element:%s\n", name);
+
+  state_processing (state, (const gchar *)name, NULL, IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT);
+}
+
+IdeXmlSymbolNode *
+ide_xml_tree_builder_ui_create (IdeXmlSax   *parser,
+                                GFile       *file,
+                                const gchar *data,
+                                gsize        length)
+{
+  ParserState *state;
+  g_autofree gchar *uri = NULL;
+
+  g_assert (IDE_IS_XML_SAX (parser));
+
+  state = g_slice_new0 (ParserState);
+  state->parser = g_object_ref (parser);
+  state->stack = ide_xml_stack_new ();
+  state->file = g_object_ref (file);
+
+  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);
+
+  state->root_node = ide_xml_symbol_node_new ("root", "root", IDE_SYMBOL_NONE, NULL, 0, 0);
+  ide_xml_stack_push (state->stack, "root", state->root_node, NULL, 0);
+
+  state->parent_node = state->root_node;
+  printf ("root node:%p\n", state->root_node);
+
+  uri = g_file_get_uri (file);
+  ide_xml_sax_parse (parser, data, length, uri, state);
+  printf ("stack size:%li\n", ide_xml_stack_get_size (state->stack));
+
+  parser_state_free (state);
+
+  return state->root_node;
+}
diff --git a/plugins/xml-pack/ide-xml-tree-builder-ui.h b/plugins/xml-pack/ide-xml-tree-builder-ui.h
new file mode 100644
index 0000000..6d6ae51
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-tree-builder-ui.h
@@ -0,0 +1,37 @@
+/* ide-xml-tree-builder-ui.h
+ *
+ * Copyright (C) 2017 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_XML_TREE_BUILDER_UI_H
+#define IDE_XML_TREE_BUILDER_UI_H
+
+#include <glib.h>
+
+#include "ide-xml-sax.h"
+#include "ide-xml-symbol-node.h"
+#include "xml-reader.h"
+
+G_BEGIN_DECLS
+
+IdeXmlSymbolNode *ide_xml_tree_builder_ui_create (IdeXmlSax   *parser,
+                                                  GFile       *file,
+                                                  const gchar *data,
+                                                  gsize        length);
+
+G_END_DECLS
+
+#endif /* IDE_XML_TREE_BUILDER_UI_H */
diff --git a/plugins/xml-pack/ide-xml-tree-builder-utils-private.h 
b/plugins/xml-pack/ide-xml-tree-builder-utils-private.h
new file mode 100644
index 0000000..038f5a5
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-tree-builder-utils-private.h
@@ -0,0 +1,36 @@
+/* ide-xml-tree-builder-utils-private.h
+ *
+ * Copyright (C) 2017 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef IDE_XML_TREE_BUILDER_UTILS_PRIVATE_H
+#define IDE_XML_TREE_BUILDER_UTILS_PRIVATE_H
+
+#include <glib.h>
+#include <ide.h>
+
+#include "ide-xml-symbol-node.h"
+
+G_BEGIN_DECLS
+
+const gchar  *list_get_attribute         (const guchar      **attributes,
+                                          const gchar        *name);
+void          print_node                 (IdeXmlSymbolNode   *node,
+                                          guint               depth);
+
+G_END_DECLS
+
+#endif /* IDE_XML_TREE_BUILDER_UTILS_PRIVATE_H */
+
diff --git a/plugins/xml-pack/ide-xml-tree-builder-utils.c b/plugins/xml-pack/ide-xml-tree-builder-utils.c
new file mode 100644
index 0000000..6298045
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-tree-builder-utils.c
@@ -0,0 +1,69 @@
+/* ide-xml-tree-builder-utils.c
+ *
+ * Copyright (C) 2017 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ide-xml-tree-builder-utils-private.h"
+
+void
+print_node (IdeXmlSymbolNode *node,
+            guint             depth)
+{
+  g_autofree gchar *spacer;
+  gint line;
+  gint line_offset;
+
+  g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (node) || node == NULL);
+
+  if (node == NULL)
+    {
+      g_warning ("Node NULL");
+      return;
+    }
+
+  spacer = g_strnfill (depth, '\t');
+  ide_xml_symbol_node_get_location (node, &line, &line_offset);
+
+  printf ("%s%s (%i) at (%i,%i) %p\n",
+          spacer,
+          ide_symbol_node_get_name (IDE_SYMBOL_NODE (node)),
+          depth,
+          line,
+          line_offset,
+          node);
+}
+
+const gchar *
+list_get_attribute (const guchar **attributes,
+                    const gchar  *name)
+{
+  const guchar **l = attributes;
+
+  g_return_val_if_fail (!ide_str_empty0 (name), NULL);
+
+  if (attributes == NULL)
+    return NULL;
+
+  while (l [0] != NULL)
+    {
+      if (ide_str_equal0 (name, l [0]))
+        return (const gchar *)l [1];
+
+      l += 2;
+    }
+
+  return NULL;
+}
diff --git a/plugins/xml-pack/ide-xml-tree-builder.c b/plugins/xml-pack/ide-xml-tree-builder.c
index d290de6..cb580f6 100644
--- a/plugins/xml-pack/ide-xml-tree-builder.c
+++ b/plugins/xml-pack/ide-xml-tree-builder.c
@@ -20,64 +20,19 @@
 #include <glib/gi18n.h>
 
 #include "xml-reader.h"
+#include "ide-xml-sax.h"
+#include "ide-xml-tree-builder-generic.h"
+#include "ide-xml-tree-builder-ui.h"
 
 #include "ide-xml-tree-builder.h"
 
-typedef GPtrArray IdeXmlStack;
-
-static inline IdeXmlStack *
-stack_new (void)
-{
-  return g_ptr_array_new ();
-}
-
-static inline void
-stack_push (IdeXmlStack *stack,
-            gpointer     ptr)
-{
-  g_ptr_array_add (stack, ptr);
-}
-
-static inline gpointer
-stack_pop (IdeXmlStack *stack)
-{
-  gint end = stack->len - 1;
-
-  return (end < 0) ? NULL : g_ptr_array_remove_index_fast (stack, end);
-}
-
-static inline gint
-stack_is_empty (IdeXmlStack *stack)
-{
-  return (stack->len == 0);
-}
-
-static inline void
-stack_destroy (IdeXmlStack *stack)
-{
-  g_ptr_array_unref (stack);
-}
-
-static inline gsize
-stack_get_size (IdeXmlStack *stack)
-{
-  return stack->len;
-}
-
-struct _IdeXmlService
-{
-  IdeObject         parent_instance;
-
-  EggTaskCache     *trees;
-  GCancellable     *cancellable;
-};
 struct _IdeXmlTreeBuilder
 {
   IdeObject parent_instance;
 };
 
 typedef struct{
-  XmlReader *reader;
+  IdeXmlSax *parser;
   GBytes    *content;
   GFile     *file;
 } BuilderState;
@@ -85,198 +40,13 @@ typedef struct{
 static void
 builder_state_free (BuilderState *state)
 {
-  g_clear_object (&state->reader);
+  g_clear_object (&state->parser);
   g_clear_pointer (&state->content, g_bytes_unref);
   g_clear_object (&state->file);
 }
 
 G_DEFINE_TYPE (IdeXmlTreeBuilder, ide_xml_tree_builder, IDE_TYPE_OBJECT)
 
-static IdeXmlSymbolNode *
-create_node_from_reader (XmlReader *reader)
-{
-  const gchar *name;
-  GFile *file = NULL;
-  guint line = 0;
-  guint line_offset = 0;
-
-  name = xml_reader_get_name (reader);
-
-  return ide_xml_symbol_node_new (name, IDE_SYMBOL_UI_OBJECT,
-                                  file, line, line_offset);
-}
-
-static void
-print_node (IdeXmlSymbolNode *node,
-            guint             depth)
-{
-  g_autofree gchar *spacer;
-
-  spacer = g_strnfill (depth, '\t');
-  printf ("%s%s (%i)\n",
-          spacer,
-          ide_symbol_node_get_name (IDE_SYMBOL_NODE (node)),
-          depth);
-}
-
-static IdeXmlSymbolNode *
-ide_xml_service_walk_tree_ui (IdeXmlTreeBuilder  *self,
-                              XmlReader          *reader)
-{
-  IdeXmlStack *stack;
-  IdeXmlSymbolNode *root_node;
-  IdeXmlSymbolNode *parent_node;
-  IdeXmlSymbolNode *current_node;
-  IdeXmlSymbolNode *previous_node = NULL;
-  xmlReaderTypes type;
-  gint depth = 0;
-  gint current_depth = 0;
-  gboolean is_empty;
-
-  g_assert (IDE_IS_XML_TREE_BUILDER (self));
-  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);
-
-          /* 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", 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);
-        }
-    }
-
-  stack_destroy (stack);
-
-  return root_node;
-}
-
-static IdeXmlSymbolNode *
-ide_xml_service_walk_tree_xml (IdeXmlTreeBuilder  *self,
-                               XmlReader          *reader)
-{
-  IdeXmlStack *stack;
-  IdeXmlSymbolNode *root_node;
-  IdeXmlSymbolNode *parent_node;
-  IdeXmlSymbolNode *current_node;
-  IdeXmlSymbolNode *previous_node = NULL;
-  xmlReaderTypes type;
-  gint depth = 0;
-  gint current_depth = 0;
-  gboolean is_empty;
-
-  g_assert (IDE_IS_XML_TREE_BUILDER (self));
-  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);
-
-          /* 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", 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);
-
-  return root_node;
-}
-
 static GBytes *
 ide_xml_service_get_file_content (IdeXmlTreeBuilder *self,
                                   GFile             *file)
@@ -356,12 +126,11 @@ build_tree_worker (GTask        *task,
 
   data = g_bytes_get_data (state->content, &size);
   uri = g_file_get_uri (state->file);
-  xml_reader_load_from_data (state->reader, data, size, uri, NULL);
 
   if (ide_xml_tree_builder_file_is_ui (state->file,data, size))
-    root_node = ide_xml_service_walk_tree_ui (self, state->reader);
+    root_node = ide_xml_tree_builder_ui_create (state->parser, state->file, data, size);
   else
-    root_node = ide_xml_service_walk_tree_xml (self, state->reader);
+    root_node = ide_xml_tree_builder_generic_create (state->parser, state->file, data, size);
 
   if (root_node == NULL)
     {
@@ -403,7 +172,7 @@ ide_xml_tree_builder_build_tree_async (IdeXmlTreeBuilder   *self,
     }
 
   state = g_slice_new0 (BuilderState);
-  state->reader = xml_reader_new ();
+  state->parser = ide_xml_sax_new ();
   state->content = g_bytes_ref (content);
   state->file = g_object_ref (file);
 



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