[gnome-builder/wip/slaf/xml-pack: 236/254] xml-pack: get the matching nodes in the rng tree



commit 3462416ed100709bc26af3aa2d72be02fdf3ea95
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Sun May 28 11:42:59 2017 +0200

    xml-pack: get the matching nodes in the rng tree
    
    One more step closer to getting some completion items.
    Here we now know for a document node, what are the
    corresponding nodes in the parsed rng schema.

 plugins/xml-pack/ide-xml-completion-provider.c |  146 +++++++++++++++++++++++-
 plugins/xml-pack/ide-xml-rng-define.c          |   73 ++++++++++++-
 plugins/xml-pack/ide-xml-rng-define.h          |   28 +++--
 plugins/xml-pack/ide-xml-symbol-node.c         |    9 ++
 plugins/xml-pack/ide-xml-symbol-node.h         |    1 +
 plugins/xml-pack/ide-xml-tree-builder.c        |    5 +-
 plugins/xml-pack/meson.build                   |    2 +
 7 files changed, 242 insertions(+), 22 deletions(-)
---
diff --git a/plugins/xml-pack/ide-xml-completion-provider.c b/plugins/xml-pack/ide-xml-completion-provider.c
index 6f4ab6a..c862511 100644
--- a/plugins/xml-pack/ide-xml-completion-provider.c
+++ b/plugins/xml-pack/ide-xml-completion-provider.c
@@ -21,8 +21,11 @@
 #include <libpeas/peas.h>
 
 #include "ide-xml-completion-provider.h"
+
+#include "ide.h"
 #include "ide-xml-path.h"
 #include "ide-xml-position.h"
+#include "ide-xml-schema-cache-entry.h"
 #include "ide-xml-service.h"
 
 struct _IdeXmlCompletionProvider
@@ -84,15 +87,143 @@ get_path (IdeXmlSymbolNode *node,
       current = ide_xml_symbol_node_get_parent (current);
     }
 
-  if (current == root_node)
-    ide_xml_path_prepend_node (path, current);
-  else
+  if (current != root_node)
     g_warning ("partial path, we don't reach the root node");
 
   return path;
 }
 
 static void
+move_candidates (GPtrArray *array,
+                 GPtrArray *sub_array)
+{
+  if (sub_array->len == 0)
+    return;
+
+  for (gint i = 0; i < sub_array->len; ++i)
+    g_ptr_array_add (array, g_ptr_array_index (sub_array, i));
+
+  g_ptr_array_remove_range (sub_array, 0, sub_array->len);
+}
+
+static void
+get_matching_nodes (IdeXmlPath       *path,
+                    gint              index,
+                    IdeXmlRngDefine  *define,
+                    GPtrArray        *candidates)
+{
+  IdeXmlSymbolNode *node;
+  IdeXmlRngDefine *child;
+  IdeXmlRngDefineType type;
+  gint current_index;
+
+  g_assert (path != NULL);
+  g_assert (define != NULL);
+  g_assert (candidates != NULL);
+
+  if (define == NULL)
+    return;
+
+  node = g_ptr_array_index (path->nodes, index);
+
+  while (define != NULL)
+    {
+      child = NULL;
+      current_index = index;
+      type = define->type;
+
+      switch (type)
+        {
+        case IDE_XML_RNG_DEFINE_ELEMENT:
+          if (ide_xml_rng_define_is_nameclass_match (define, node))
+            {
+              ++current_index;
+              child = define->content;
+            }
+
+          break;
+
+        case IDE_XML_RNG_DEFINE_NOOP:
+        case IDE_XML_RNG_DEFINE_NOTALLOWED:
+        case IDE_XML_RNG_DEFINE_TEXT:
+        case IDE_XML_RNG_DEFINE_DATATYPE:
+        case IDE_XML_RNG_DEFINE_VALUE:
+        case IDE_XML_RNG_DEFINE_EMPTY:
+        case IDE_XML_RNG_DEFINE_ATTRIBUTE:
+        case IDE_XML_RNG_DEFINE_START:
+        case IDE_XML_RNG_DEFINE_PARAM:
+        case IDE_XML_RNG_DEFINE_EXCEPT:
+        case IDE_XML_RNG_DEFINE_LIST:
+          break;
+
+        case IDE_XML_RNG_DEFINE_DEFINE:
+        case IDE_XML_RNG_DEFINE_REF:
+        case IDE_XML_RNG_DEFINE_PARENTREF:
+        case IDE_XML_RNG_DEFINE_EXTERNALREF:
+          child = define->content;
+          break;
+
+        case IDE_XML_RNG_DEFINE_ZEROORMORE:
+        case IDE_XML_RNG_DEFINE_ONEORMORE:
+        case IDE_XML_RNG_DEFINE_OPTIONAL:
+        case IDE_XML_RNG_DEFINE_CHOICE:
+        case IDE_XML_RNG_DEFINE_GROUP:
+        case IDE_XML_RNG_DEFINE_INTERLEAVE:
+          child = define->content;
+          break;
+
+        default:
+          g_assert_not_reached ();
+        }
+
+      if (current_index == path->nodes->len)
+        g_ptr_array_add (candidates, define);
+      else if (child != NULL)
+        get_matching_nodes (path, current_index, child, candidates);
+
+      define = define->next;
+    }
+}
+
+static GPtrArray *
+get_matching_candidates (IdeXmlCompletionProvider *self,
+                         GPtrArray                *schemas,
+                         IdeXmlPath               *path)
+{
+  GPtrArray *candidates;
+  g_autoptr (GPtrArray) candidates_tmp = NULL;
+  g_autoptr (GPtrArray) defines = NULL;
+  IdeXmlSchemaCacheEntry *schema_entry;
+  IdeXmlSchema *schema;
+  IdeXmlRngGrammar *grammar;
+
+  g_assert (IDE_IS_XML_COMPLETION_PROVIDER (self));
+  g_assert (schemas != NULL);
+  g_assert (path != NULL && path->nodes->len > 0);
+
+  candidates = g_ptr_array_new ();
+  candidates_tmp = g_ptr_array_sized_new (16);
+  defines = g_ptr_array_new ();
+
+  for (gint i = 0; i < schemas->len; ++i)
+    {
+      schema_entry = g_ptr_array_index (schemas, i);
+      /* TODO: only RNG for now */
+      if (schema_entry->kind != SCHEMA_KIND_RNG ||
+          schema_entry->state != SCHEMA_STATE_PARSED)
+        continue;
+
+      schema = schema_entry->schema;
+      grammar = schema->top_grammar;
+
+      get_matching_nodes (path, 0, grammar->start_defines, candidates_tmp);
+      move_candidates (candidates, candidates_tmp);
+    }
+
+  return candidates;
+}
+
+static void
 populate_cb (GObject      *object,
              GAsyncResult *result,
              gpointer      user_data)
@@ -104,11 +235,13 @@ populate_cb (GObject      *object,
   IdeXmlSymbolNode *root_node, *node;
   IdeXmlAnalysis *analysis;
   IdeXmlPositionKind kind;
-  IdeXmlPath *path;
+  g_autoptr (IdeXmlPath) path = NULL;
   GtkSourceCompletionItem *item;
   g_autofree gchar *text = NULL;
   g_autofree gchar *label = NULL;
   g_autoptr (GList) results = NULL;
+  GPtrArray *schemas;
+  g_autoptr (GPtrArray) candidates = NULL;
   GError *error = NULL;
 
   g_assert (IDE_IS_XML_COMPLETION_PROVIDER (self));
@@ -116,12 +249,17 @@ populate_cb (GObject      *object,
 
   position = ide_xml_service_get_position_from_cursor_finish (service, result, &error);
   analysis = ide_xml_position_get_analysis (position);
+  schemas = ide_xml_analysis_get_schemas (analysis);
   root_node = ide_xml_analysis_get_root_node (analysis);
   node = ide_xml_position_get_node (position);
   kind = ide_xml_position_get_kind (position);
 
   path = get_path (node, root_node);
 
+  if (schemas != NULL)
+    candidates = get_matching_candidates (self, schemas, path);
+
+
   text = g_strdup ("xml item text");
   label = g_strdup ("xml item label");
   item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
diff --git a/plugins/xml-pack/ide-xml-rng-define.c b/plugins/xml-pack/ide-xml-rng-define.c
index 24777df..2e64b17 100644
--- a/plugins/xml-pack/ide-xml-rng-define.c
+++ b/plugins/xml-pack/ide-xml-rng-define.c
@@ -46,6 +46,14 @@ static gchar *type_names [] =
   "except"
 };
 
+const gchar *
+ide_xml_rng_define_get_type_name (IdeXmlRngDefine *self)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+
+  return type_names [self->type];
+}
+
 static void
 dump_tree (IdeXmlRngDefine *self,
            gint             indent)
@@ -58,8 +66,10 @@ dump_tree (IdeXmlRngDefine *self,
   pad = g_strnfill (indent, ' ');
   while (def != NULL)
     {
-      type_name = type_names [def->type];
-      if (def->type == IDE_XML_RNG_DEFINE_REF || def->type == IDE_XML_RNG_DEFINE_PARENTREF)
+      type_name = ide_xml_rng_define_get_type_name (def);
+      if (def->type == IDE_XML_RNG_DEFINE_REF ||
+          def->type == IDE_XML_RNG_DEFINE_PARENTREF ||
+          def->type == IDE_XML_RNG_DEFINE_EXTERNALREF)
         {
           if (def->node != NULL &&
               NULL != (name = xmlGetProp (def->node, (const guchar *)"name")))
@@ -218,3 +228,62 @@ ide_xml_rng_define_propagate_parent (IdeXmlRngDefine *self,
       last = last->next;
     } while (last != NULL);
 }
+
+gboolean
+ide_xml_rng_define_is_nameclass_match (IdeXmlRngDefine  *define,
+                                       IdeXmlSymbolNode *node)
+{
+  const gchar *name;
+  const gchar *namespace;
+  IdeXmlRngDefine *nc;
+  IdeXmlRngDefine *content;
+
+  g_assert (IDE_IS_XML_SYMBOL_NODE (node));
+  g_assert (define != NULL);
+
+  name = ide_xml_symbol_node_get_element_name (node);
+  namespace = ide_xml_symbol_node_get_namespace (node);
+
+  if (define->name != NULL && !ide_str_equal0 (name, define->name))
+    return FALSE;
+
+  if (!ide_str_empty0 ((const gchar *)define->ns))
+    {
+      if (namespace == NULL || !ide_str_equal0 (define->ns, namespace))
+        return FALSE;
+    }
+  else if (namespace != NULL && (define->name != NULL || define->ns != NULL))
+    return FALSE;
+
+ if (NULL == (nc = define->name_class))
+   return TRUE;
+
+  if (nc->type == IDE_XML_RNG_DEFINE_EXCEPT)
+    {
+      content = nc->content;
+      while (content != NULL)
+        {
+          if (ide_xml_rng_define_is_nameclass_match (content, node))
+            return FALSE;
+
+          content = content->next;
+        }
+
+      return TRUE;
+    }
+  else if (nc->type == IDE_XML_RNG_DEFINE_CHOICE)
+    {
+      content = define->name_class;
+      while (content != NULL)
+        {
+          if (ide_xml_rng_define_is_nameclass_match (content, node))
+            return TRUE;
+
+          content = content->next;
+        }
+
+      return FALSE;
+    }
+  else
+    g_assert_not_reached ();
+}
diff --git a/plugins/xml-pack/ide-xml-rng-define.h b/plugins/xml-pack/ide-xml-rng-define.h
index 1bf49df..28136e9 100644
--- a/plugins/xml-pack/ide-xml-rng-define.h
+++ b/plugins/xml-pack/ide-xml-rng-define.h
@@ -21,6 +21,7 @@
 
 #include <libxml/tree.h>
 #include <glib-object.h>
+#include "ide-xml-symbol-node.h"
 
 G_BEGIN_DECLS
 
@@ -73,18 +74,21 @@ struct _IdeXmlRngDefine
   guint                is_ref_simplified : 1;
 };
 
-IdeXmlRngDefine     *ide_xml_rng_define_new              (xmlNode             *node,
-                                                          IdeXmlRngDefine     *parent,
-                                                          const guchar        *name,
-                                                          IdeXmlRngDefineType  type);
-void                 ide_xml_rng_define_append           (IdeXmlRngDefine     *self,
-                                                          IdeXmlRngDefine     *def);
-void                 ide_xml_rng_define_propagate_parent (IdeXmlRngDefine     *self,
-                                                          IdeXmlRngDefine     *parent);
-IdeXmlRngDefine     *ide_xml_rng_define_ref              (IdeXmlRngDefine     *self);
-void                 ide_xml_rng_define_unref            (IdeXmlRngDefine     *self);
-void                 ide_xml_rng_define_dump_tree        (IdeXmlRngDefine     *self,
-                                                          gboolean             recursive);
+IdeXmlRngDefine     *ide_xml_rng_define_new                 (xmlNode             *node,
+                                                             IdeXmlRngDefine     *parent,
+                                                             const guchar        *name,
+                                                             IdeXmlRngDefineType  type);
+void                 ide_xml_rng_define_append              (IdeXmlRngDefine     *self,
+                                                             IdeXmlRngDefine     *def);
+const gchar         *ide_xml_rng_define_get_type_name       (IdeXmlRngDefine     *self);
+gboolean             ide_xml_rng_define_is_nameclass_match  (IdeXmlRngDefine     *define,
+                                                             IdeXmlSymbolNode    *node);
+void                 ide_xml_rng_define_propagate_parent    (IdeXmlRngDefine     *self,
+                                                             IdeXmlRngDefine     *parent);
+IdeXmlRngDefine     *ide_xml_rng_define_ref                 (IdeXmlRngDefine     *self);
+void                 ide_xml_rng_define_unref               (IdeXmlRngDefine     *self);
+void                 ide_xml_rng_define_dump_tree           (IdeXmlRngDefine     *self,
+                                                             gboolean             recursive);
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeXmlRngDefine, ide_xml_rng_define_unref)
 
diff --git a/plugins/xml-pack/ide-xml-symbol-node.c b/plugins/xml-pack/ide-xml-symbol-node.c
index d1fc4cc..43a758f 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.c
+++ b/plugins/xml-pack/ide-xml-symbol-node.c
@@ -48,6 +48,7 @@ struct _IdeXmlSymbolNode
   gint               nb_internal_children;
   GFile             *file;
   gchar            **attributes_names;
+  gchar             *ns;
   NodeRange          start_tag;
   NodeRange          end_tag;
 
@@ -686,3 +687,11 @@ ide_xml_symbol_node_print (IdeXmlSymbolNode  *self,
   if (show_value && self->value != NULL)
     printf ("\t%s\n", self->value);
 }
+
+const gchar *
+ide_xml_symbol_node_get_namespace (IdeXmlSymbolNode  *self)
+{
+  g_return_val_if_fail (IDE_IS_XML_SYMBOL_NODE (self), NULL);
+
+  return self->ns;
+}
diff --git a/plugins/xml-pack/ide-xml-symbol-node.h b/plugins/xml-pack/ide-xml-symbol-node.h
index a776c57..cdb5cd3 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.h
+++ b/plugins/xml-pack/ide-xml-symbol-node.h
@@ -54,6 +54,7 @@ void                      ide_xml_symbol_node_get_end_tag_location          (Ide
                                                                              gint                   
*end_line,
                                                                              gint                   
*end_line_offset,
                                                                              gsize                  *size);
+const gchar              *ide_xml_symbol_node_get_namespace                 (IdeXmlSymbolNode       *self);
 guint                     ide_xml_symbol_node_get_n_children                (IdeXmlSymbolNode       *self);
 guint                     ide_xml_symbol_node_get_n_internal_children       (IdeXmlSymbolNode       *self);
 IdeSymbolNode            *ide_xml_symbol_node_get_nth_child                 (IdeXmlSymbolNode       *self,
diff --git a/plugins/xml-pack/ide-xml-tree-builder.c b/plugins/xml-pack/ide-xml-tree-builder.c
index a344ab3..6136abf 100644
--- a/plugins/xml-pack/ide-xml-tree-builder.c
+++ b/plugins/xml-pack/ide-xml-tree-builder.c
@@ -355,10 +355,7 @@ ide_xml_tree_builder_build_tree_cb2 (GObject      *object,
           if (ide_xml_validator_validate (self->validator, doc, &diagnostics))
             printf ("validated\n");
           else
-            {
-              printf ("NOT validated\n");
-              entry->state = SCHEMA_STATE_CANT_VALIDATE;
-            }
+            printf ("NOT validated\n");
 
           ide_diagnostics_merge (state->analysis->diagnostics, diagnostics);
         }
diff --git a/plugins/xml-pack/meson.build b/plugins/xml-pack/meson.build
index 535191a..7e6bf7c 100644
--- a/plugins/xml-pack/meson.build
+++ b/plugins/xml-pack/meson.build
@@ -23,6 +23,8 @@ xml_pack_sources = [
   'ide-xml-path.h',
   'ide-xml-position.c',
   'ide-xml-position.h',
+  'ide-xml-rng-define.c',
+  'ide-xml-rng-define.h',
   'ide-xml-rng-grammar.c',
   'ide-xml-rng-grammar.h',
   'ide-xml-rng-parser.c',


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