[gnome-builder] xml-pack: start autocompletion on attributes value



commit 997fedf20099846f79a81264710dc8ed0cf188b3
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Tue Jul 18 18:35:34 2017 +0200

    xml-pack: start autocompletion on attributes value

 plugins/xml-pack/ide-xml-completion-attributes.c |   23 +-
 plugins/xml-pack/ide-xml-completion-attributes.h |   10 +-
 plugins/xml-pack/ide-xml-completion-provider.c   |   98 +++++++-
 plugins/xml-pack/ide-xml-completion-values.c     |  301 ++++++++++++++++++++++
 plugins/xml-pack/ide-xml-completion-values.h     |   42 +++
 plugins/xml-pack/ide-xml-parser.c                |   26 +--
 plugins/xml-pack/ide-xml-position.c              |   17 +-
 plugins/xml-pack/ide-xml-rng-define.c            |    4 +-
 plugins/xml-pack/ide-xml-rng-parser.c            |    5 +-
 plugins/xml-pack/ide-xml-symbol-node.c           |   88 +++++--
 plugins/xml-pack/ide-xml-symbol-node.h           |    8 +-
 plugins/xml-pack/meson.build                     |    2 +
 12 files changed, 551 insertions(+), 73 deletions(-)
---
diff --git a/plugins/xml-pack/ide-xml-completion-attributes.c 
b/plugins/xml-pack/ide-xml-completion-attributes.c
index ea1f5e3..3efe176 100644
--- a/plugins/xml-pack/ide-xml-completion-attributes.c
+++ b/plugins/xml-pack/ide-xml-completion-attributes.c
@@ -36,9 +36,10 @@ static GPtrArray * process_matching_state (MatchingState   *state,
                                            IdeXmlRngDefine *define);
 
 static MatchItem *
-match_item_new (const gchar *attr_name,
-                gint         attr_pos,
-                gboolean     is_optional)
+match_item_new (IdeXmlRngDefine *define,
+                const gchar     *attr_name,
+                gint             attr_pos,
+                gboolean         is_optional)
 {
   MatchItem *item;
 
@@ -46,6 +47,7 @@ match_item_new (const gchar *attr_name,
 
   item = g_slice_new0 (MatchItem);
 
+  item->define = define;
   item->name = g_strdup (attr_name);
   item->pos = attr_pos;
   item->is_optional = is_optional;
@@ -83,7 +85,7 @@ match_children_add (GPtrArray *to_children,
   for (gint i = 0; i < from_children->len; ++i)
     {
       from_item = g_ptr_array_index (from_children, i);
-      to_item = match_item_new (from_item->name, from_item->pos, from_item->is_optional);
+      to_item = match_item_new (from_item->define, from_item->name, from_item->pos, from_item->is_optional);
       g_ptr_array_add (to_children, to_item);
     }
 }
@@ -132,7 +134,7 @@ process_attribute (MatchingState *state)
   if (ide_str_empty0 (name))
     return match_children;
 
-  item = match_item_new (name, state->define->pos, state->is_optional);
+  item = match_item_new (state->define, name, state->define->pos, state->is_optional);
   g_ptr_array_add (match_children, item);
 
   return match_children;
@@ -367,7 +369,7 @@ create_initial_matching_state (IdeXmlRngDefine  *define,
                                IdeXmlSymbolNode *node)
 {
   MatchingState *state;
-  const gchar **attributes;
+  gchar **attributes;
 
   g_assert (define != NULL);
 
@@ -378,6 +380,8 @@ create_initial_matching_state (IdeXmlRngDefine  *define,
         {
           for (gint i = 0; attributes [i] != NULL; i++)
             g_ptr_array_add (state->node_attr, (gchar *)attributes [i]);
+
+          g_free (attributes);
         }
     }
 
@@ -555,7 +559,8 @@ set_attributes_position (MatchingState   *state,
 /* Return an array of MatchItem */
 GPtrArray *
 ide_xml_completion_attributes_get_matches (IdeXmlRngDefine  *define,
-                                           IdeXmlSymbolNode *node)
+                                           IdeXmlSymbolNode *node,
+                                           gboolean          filtered)
 {
   MatchingState *initial_state;
   GPtrArray *match_children;
@@ -571,7 +576,9 @@ ide_xml_completion_attributes_get_matches (IdeXmlRngDefine  *define,
 
   initial_state->is_initial_state = TRUE;
   match_children = process_matching_state (initial_state, define);
-  match_children_filter (match_children, initial_state->node_attr);
+
+  if (filtered)
+    match_children_filter (match_children, initial_state->node_attr);
 
   matching_state_free (initial_state);
   return match_children;
diff --git a/plugins/xml-pack/ide-xml-completion-attributes.h 
b/plugins/xml-pack/ide-xml-completion-attributes.h
index bcd7cef..a029485 100644
--- a/plugins/xml-pack/ide-xml-completion-attributes.h
+++ b/plugins/xml-pack/ide-xml-completion-attributes.h
@@ -30,13 +30,15 @@ G_BEGIN_DECLS
 
 typedef struct _MatchItem
 {
-  gchar    *name;
-  gint      pos;
-  gboolean  is_optional;
+  IdeXmlRngDefine *define;
+  gchar           *name;
+  gint             pos;
+  gboolean         is_optional;
 } MatchItem;
 
 GPtrArray           *ide_xml_completion_attributes_get_matches       (IdeXmlRngDefine     *define,
-                                                                      IdeXmlSymbolNode    *node);
+                                                                      IdeXmlSymbolNode    *node,
+                                                                      gboolean             filtered);
 
 G_END_DECLS
 
diff --git a/plugins/xml-pack/ide-xml-completion-provider.c b/plugins/xml-pack/ide-xml-completion-provider.c
index bdc2750..f19e147 100644
--- a/plugins/xml-pack/ide-xml-completion-provider.c
+++ b/plugins/xml-pack/ide-xml-completion-provider.c
@@ -24,6 +24,7 @@
 
 #include "ide.h"
 #include "ide-xml-completion-attributes.h"
+#include "ide-xml-completion-values.h"
 #include "ide-xml-path.h"
 #include "ide-xml-position.h"
 #include "ide-xml-rng-define.h"
@@ -776,12 +777,12 @@ get__element_proposals (IdeXmlPosition *position,
   if (ide_xml_position_get_kind (position) == IDE_XML_POSITION_KIND_IN_CONTENT)
     start = "<";
 
-  for (gint j = 0; j < items->len; ++j)
+  for (gint i = 0; i < items->len; ++i)
     {
       g_autofree gchar *label = NULL;
       g_autofree gchar *text = NULL;
 
-      completion_item = g_ptr_array_index (items, j);
+      completion_item = g_ptr_array_index (items, i);
       label = g_strconcat ("<", completion_item->label, ">", NULL);
       text = g_strconcat (start, completion_item->label, ">", "</", completion_item->label, ">", NULL);
       item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
@@ -805,15 +806,15 @@ get_attributes_proposals (IdeXmlPosition  *position,
   GList *results = NULL;
 
   node = ide_xml_position_get_child_node (position);
-  if (NULL != (attributes = ide_xml_completion_attributes_get_matches (define, node)))
+  if (NULL != (attributes = ide_xml_completion_attributes_get_matches (define, node, TRUE)))
     {
-      for (gint j = 0; j < attributes->len; ++j)
+      for (gint i = 0; i < attributes->len; ++i)
         {
           g_autofree gchar *name = NULL;
           g_autofree gchar *text = NULL;
           MatchItem *match_item;
 
-          match_item = g_ptr_array_index (attributes, j);
+          match_item = g_ptr_array_index (attributes, i);
           /* XXX: can't get the markup working, add () */
           if (match_item->is_optional)
             name = g_strconcat ("<i>(", match_item->name, ")</i>", NULL);
@@ -833,6 +834,65 @@ get_attributes_proposals (IdeXmlPosition  *position,
   return results;
 }
 
+static GList *
+get_values_proposals (IdeXmlPosition  *position,
+                      IdeXmlRngDefine *define)
+{
+  IdeXmlSymbolNode *node;
+  IdeXmlRngDefine *attr_define = NULL;
+  g_autoptr(GPtrArray) attributes = NULL;
+  g_autoptr(GPtrArray) values = NULL;
+  GtkSourceCompletionItem *item;
+  GList *results = NULL;
+
+  node = ide_xml_position_get_child_node (position);
+  g_assert (!ide_str_empty0 (position->detail_name));
+
+  if (NULL != (attributes = ide_xml_completion_attributes_get_matches (define, node, FALSE)))
+    {
+      MatchItem *match_item;
+      const gchar *detail_name;
+      const gchar *detail_value;
+      const gchar *content;
+
+      detail_name = ide_xml_position_get_detail_name (position);
+      detail_value = ide_xml_position_get_detail_value (position);
+
+      for (gint j = 0; j < attributes->len; ++j)
+        {
+          match_item = g_ptr_array_index (attributes, j);
+          if (ide_str_equal0 (detail_name, match_item->name))
+            {
+              attr_define = match_item->define;
+              break;
+            }
+        }
+
+      if (attr_define != NULL)
+        {
+          ide_xml_symbol_node_print (node, 0, FALSE, TRUE, TRUE);
+          content = ide_xml_symbol_node_get_attribute_value (node, match_item->name);
+
+          if (NULL != (values = ide_xml_completion_values_get_matches (attr_define, content, detail_value)))
+            {
+              for (gint i = 0; i < values->len; ++i)
+                {
+                  ValueMatchItem *value_match_item = g_ptr_array_index (values, i);
+
+                  item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
+                                       "markup", value_match_item->name,
+                                       "text", value_match_item->name,
+                                       NULL);
+
+                  results = g_list_prepend (results, item);
+                }
+            }
+        }
+    }
+
+  return results;
+}
+
 static void
 populate_cb (GObject      *object,
              GAsyncResult *result,
@@ -854,7 +914,8 @@ populate_cb (GObject      *object,
   g_autoptr (GPtrArray) items = NULL;
   GError *error = NULL;
   gint child_pos;
-  gboolean complete_attributes;
+  gboolean complete_attributes = FALSE;
+  gboolean complete_values = FALSE;
 
   g_assert (IDE_IS_XML_COMPLETION_PROVIDER (self));
   g_assert (IDE_IS_XML_SERVICE (service));
@@ -868,10 +929,15 @@ populate_cb (GObject      *object,
   detail = ide_xml_position_get_detail (position);
   child_pos = ide_xml_position_get_child_pos (position);
 
-  complete_attributes = ((kind == IDE_XML_POSITION_KIND_IN_START_TAG || kind == 
IDE_XML_POSITION_KIND_IN_END_TAG) &&
-                         detail == IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_NAME);
+  if (kind == IDE_XML_POSITION_KIND_IN_START_TAG || kind == IDE_XML_POSITION_KIND_IN_END_TAG)
+    {
+      if (detail == IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_NAME)
+        complete_attributes = TRUE;
+      else if (detail == IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_VALUE)
+        complete_values = TRUE;
+    }
 
-  if (complete_attributes)
+  if (complete_attributes || complete_values)
     {
       IdeXmlSymbolNode *child_node;
 
@@ -902,6 +968,20 @@ populate_cb (GObject      *object,
                                                            TRUE);
             }
         }
+      else if (complete_values)
+        {
+          for (gint i = 0; i < candidates->len; ++i)
+            {
+              g_autoptr (GList) results = NULL;
+
+              def = g_ptr_array_index (candidates, i);
+              results = get_values_proposals (position, def);
+              gtk_source_completion_context_add_proposals (state->completion_context,
+                                                           GTK_SOURCE_COMPLETION_PROVIDER (self),
+                                                           results,
+                                                           TRUE);
+            }
+        }
       else
         {
           g_autoptr (GList) results = NULL;
diff --git a/plugins/xml-pack/ide-xml-completion-values.c b/plugins/xml-pack/ide-xml-completion-values.c
new file mode 100644
index 0000000..333c16d
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-completion-values.c
@@ -0,0 +1,301 @@
+/* ide-xml-completion-values.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-completion-values.h"
+#include "ide-xml-position.h"
+
+typedef struct _MatchingState
+{
+  IdeXmlRngDefine  *define;
+  GPtrArray        *match_values;
+  const gchar      *values;
+  const gchar      *prefix;
+
+  guint             is_initial_state : 1;
+} MatchingState;
+
+static GPtrArray * process_matching_state (MatchingState   *state,
+                                           IdeXmlRngDefine *define);
+
+static ValueMatchItem *
+value_match_item_new (const gchar *value)
+{
+  ValueMatchItem *item;
+
+  g_assert (!ide_str_empty0 (value));
+
+  item = g_slice_new0 (ValueMatchItem);
+  item->name = g_strdup (value);
+
+  return item;
+}
+
+static void
+value_match_item_free (gpointer data)
+{
+  ValueMatchItem *item = (ValueMatchItem *)data;
+
+  g_clear_pointer (&item->name, g_free);
+  g_slice_free (ValueMatchItem, item);
+}
+
+static GPtrArray *
+match_values_new (void)
+{
+  GPtrArray *ar;
+
+  ar = g_ptr_array_new_with_free_func ((GDestroyNotify)value_match_item_free);
+  return ar;
+}
+
+static void
+match_values_add (GPtrArray *to_values,
+                  GPtrArray *from_values)
+{
+  ValueMatchItem *to_item;
+  ValueMatchItem *from_item;
+
+  g_assert (to_values != NULL);
+
+  if (from_values == NULL)
+    return;
+
+  for (gint i = 0; i < from_values->len; ++i)
+    {
+      from_item = g_ptr_array_index (from_values, i);
+      to_item = value_match_item_new (from_item->name);
+      g_ptr_array_add (to_values, to_item);
+    }
+}
+
+static MatchingState *
+matching_state_new (IdeXmlRngDefine  *define,
+                    const gchar      *values,
+                    const gchar      *prefix)
+{
+  MatchingState *state;
+
+  g_assert (define != NULL);
+
+  state = g_slice_new0 (MatchingState);
+
+  state->define = define;
+  state->values = (values != NULL) ? g_strdup (values) : NULL;
+  state->prefix = (prefix != NULL) ? g_strdup (prefix) : NULL;
+
+  state->is_initial_state = FALSE;
+
+  return state;
+}
+
+static void
+matching_state_free (MatchingState *state)
+{
+  g_clear_pointer (&state->values, g_free);
+  g_clear_pointer (&state->prefix, g_free);
+}
+
+static GPtrArray *
+process_value (MatchingState *state)
+{
+  GPtrArray *match_values = NULL;
+  ValueMatchItem *item;
+  const gchar *value;
+
+  g_assert (state->define->type == IDE_XML_RNG_DEFINE_VALUE);
+
+  value = (gchar *)state->define->name;
+
+  if (!ide_str_empty0 (value) &&
+      (ide_str_empty0 (state->prefix) || g_str_has_prefix (value, state->prefix)))
+    {
+      match_values = match_values_new ();
+      item = value_match_item_new (value);
+      g_ptr_array_add (match_values, item);
+    }
+
+  return match_values;
+}
+
+static GPtrArray *
+process_choice (MatchingState *state)
+{
+  GPtrArray *match_values = NULL;
+  IdeXmlRngDefine *defines;
+
+  g_assert (state->define->type == IDE_XML_RNG_DEFINE_CHOICE);
+
+  if (NULL != (defines = state->define->content))
+    {
+      match_values = match_values_new ();
+      while (defines != NULL)
+        {
+          g_autoptr (GPtrArray) match = NULL;
+
+          if (NULL != (match = process_matching_state (state, defines)))
+            {
+              /* TODO: use move */
+              match_values_add (match_values, match);
+            }
+
+          defines = defines->next;
+        }
+    }
+
+  return match_values;
+}
+
+static GPtrArray *
+process_group (MatchingState *state)
+{
+  GPtrArray *match_values = NULL;
+  IdeXmlRngDefine *defines;
+
+  g_assert (state->define->type == IDE_XML_RNG_DEFINE_GROUP ||
+            state->define->type == IDE_XML_RNG_DEFINE_ATTRIBUTE ||
+            state->define->type == IDE_XML_RNG_DEFINE_ZEROORMORE ||
+            state->define->type == IDE_XML_RNG_DEFINE_ONEORMORE ||
+            state->define->type == IDE_XML_RNG_DEFINE_OPTIONAL);
+
+  if (NULL != (defines = state->define->content))
+    {
+      while (defines != NULL)
+        {
+          g_autoptr (GPtrArray) match = NULL;
+
+          match_values = match_values_new ();
+          if (NULL != (match = process_matching_state (state, defines)))
+            {
+              match_values_add (match_values, match);
+            }
+
+          defines = defines->next;
+        }
+    }
+
+  return match_values;
+}
+
+static GPtrArray *
+process_matching_state (MatchingState   *state,
+                        IdeXmlRngDefine *define)
+{
+  IdeXmlRngDefine *old_define;
+  IdeXmlRngDefineType type;
+  GPtrArray *match_values;
+
+  g_assert (state != NULL);
+  g_assert (define != NULL);
+
+  old_define = state->define;
+  state->define = define;
+
+  if (state->is_initial_state)
+    {
+      state->is_initial_state = FALSE;
+      type = IDE_XML_RNG_DEFINE_GROUP;
+    }
+  else
+    type = define->type;
+
+  switch (type)
+    {
+    case IDE_XML_RNG_DEFINE_VALUE:
+      match_values = process_value (state);
+      break;
+
+    case IDE_XML_RNG_DEFINE_ATTRIBUTE:
+    case IDE_XML_RNG_DEFINE_ATTRIBUTES_GROUP:
+    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_EMPTY:
+    case IDE_XML_RNG_DEFINE_ELEMENT:
+    case IDE_XML_RNG_DEFINE_START:
+    case IDE_XML_RNG_DEFINE_PARAM:
+    case IDE_XML_RNG_DEFINE_EXCEPT:
+    case IDE_XML_RNG_DEFINE_LIST:
+      match_values = NULL;
+      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:
+      match_values = process_matching_state (state, define->content);
+      break;
+
+    case IDE_XML_RNG_DEFINE_INTERLEAVE:
+    case IDE_XML_RNG_DEFINE_GROUP:
+    case IDE_XML_RNG_DEFINE_ZEROORMORE:
+    case IDE_XML_RNG_DEFINE_ONEORMORE:
+    case IDE_XML_RNG_DEFINE_OPTIONAL:
+      match_values = process_group (state);
+      break;
+
+    case IDE_XML_RNG_DEFINE_CHOICE:
+      match_values = process_choice (state);
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  state->define = old_define;
+
+  return match_values;
+}
+
+static MatchingState *
+create_initial_matching_state (IdeXmlRngDefine  *define,
+                               const gchar      *values,
+                               const gchar      *prefix)
+{
+  MatchingState *state;
+
+  g_assert (define != NULL);
+
+  state = matching_state_new (define, values, prefix);
+  state->is_initial_state = TRUE;
+
+  return state;
+}
+
+/* Return an array of ValueMatchItem */
+GPtrArray *
+ide_xml_completion_values_get_matches (IdeXmlRngDefine *define,
+                                       const gchar     *values,
+                                       const gchar     *prefix)
+{
+  MatchingState *initial_state;
+  GPtrArray *match_values = NULL;
+
+  g_return_val_if_fail (define != NULL, NULL);
+
+  if (define->content != NULL)
+    {
+      initial_state = create_initial_matching_state (define, values, prefix);
+
+      initial_state->is_initial_state = TRUE;
+      match_values = process_matching_state (initial_state, define);
+      matching_state_free (initial_state);
+    }
+
+  return match_values;
+}
diff --git a/plugins/xml-pack/ide-xml-completion-values.h b/plugins/xml-pack/ide-xml-completion-values.h
new file mode 100644
index 0000000..07baae7
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-completion-values.h
@@ -0,0 +1,42 @@
+/* ide-xml-completion-values.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_COMPLETION_VALUES_H
+#define IDE_XML_COMPLETION_VALUES_H
+
+#include <glib.h>
+
+#include <ide.h>
+
+#include "ide-xml-rng-define.h"
+#include "ide-xml-symbol-node.h"
+
+G_BEGIN_DECLS
+
+typedef struct _ValueMatchItem
+{
+  gchar    *name;
+} ValueMatchItem;
+
+GPtrArray           *ide_xml_completion_values_get_matches       (IdeXmlRngDefine *define,
+                                                                  const gchar     *values,
+                                                                  const gchar     *prefix);
+
+G_END_DECLS
+
+#endif /* IDE_XML_COMPLETION_VALUES_H */
diff --git a/plugins/xml-pack/ide-xml-parser.c b/plugins/xml-pack/ide-xml-parser.c
index cfa399a..3a6cc83 100644
--- a/plugins/xml-pack/ide-xml-parser.c
+++ b/plugins/xml-pack/ide-xml-parser.c
@@ -150,28 +150,6 @@ ide_xml_parser_create_diagnostic (ParserState            *state,
   return diagnostic;
 }
 
-static gchar **
-fetch_attributes_names (IdeXmlParser  *self,
-                        const gchar  **attributes)
-{
-  GPtrArray *attrs;
-
-  g_assert (IDE_IS_XML_PARSER (self));
-
-  if (attributes == NULL)
-    return NULL;
-
-  attrs = g_ptr_array_new ();
-  while (attributes [0] != NULL)
-    {
-      g_ptr_array_add (attrs, g_strdup (attributes [0]));
-      attributes += 2;
-    }
-
-  g_ptr_array_add (attrs, NULL);
-  return (gchar**)g_ptr_array_free (attrs, FALSE);
-}
-
 void
 ide_xml_parser_state_processing (IdeXmlParser          *self,
                                  ParserState           *state,
@@ -236,7 +214,7 @@ ide_xml_parser_state_processing (IdeXmlParser          *self,
           ide_xml_symbol_node_take_internal_child (state->parent_node, node);
           state->parent_node = node;
 
-          ide_xml_symbol_node_take_attributes_names (node, fetch_attributes_names (self, state->attributes));
+          ide_xml_symbol_node_set_attributes (node, state->attributes);
           state->attributes = NULL;
         }
       else if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT)
@@ -292,7 +270,7 @@ ide_xml_parser_state_processing (IdeXmlParser          *self,
         ide_xml_symbol_node_take_child (state->parent_node, node);
 
       state->parent_node = node;
-      ide_xml_symbol_node_take_attributes_names (node, fetch_attributes_names (self, state->attributes));
+      ide_xml_symbol_node_set_attributes (node, state->attributes);
       state->attributes = NULL;
     }
   else if (callback_type == IDE_XML_SAX_CALLBACK_TYPE_END_ELEMENT)
diff --git a/plugins/xml-pack/ide-xml-position.c b/plugins/xml-pack/ide-xml-position.c
index bcd95ae..29312d3 100644
--- a/plugins/xml-pack/ide-xml-position.c
+++ b/plugins/xml-pack/ide-xml-position.c
@@ -296,16 +296,25 @@ ide_xml_position_print (IdeXmlPosition *self)
 
   if (self->node != NULL)
     {
-      const gchar **attributes_names;
+      gchar **attributes_names;
+      gchar **attributes_names_cursor;
       IdeXmlSymbolNode *node;
 
       if (NULL != (attributes_names = ide_xml_symbol_node_get_attributes_names (self->node)))
         {
-          while (attributes_names [0] != NULL)
+          attributes_names_cursor = attributes_names;
+          while (attributes_names_cursor [0] != NULL)
             {
-              printf ("attr:%s\n", *attributes_names);
-              ++attributes_names;
+              g_autofree gchar *name = NULL;
+              const gchar *value;
+
+              name = g_strdup (attributes_names [0]);
+              value = ide_xml_symbol_node_get_attribute_value (self->node, name);
+              printf ("attr:%s=%s\n", name, value);
+              ++attributes_names_cursor;
             }
+
+          g_strfreev (attributes_names);
         }
 
       if ((n_children = ide_xml_symbol_node_get_n_direct_children (self->node)) > 0)
diff --git a/plugins/xml-pack/ide-xml-rng-define.c b/plugins/xml-pack/ide-xml-rng-define.c
index a8f0f5d..9e60f74 100644
--- a/plugins/xml-pack/ide-xml-rng-define.c
+++ b/plugins/xml-pack/ide-xml-rng-define.c
@@ -170,10 +170,10 @@ ide_xml_rng_define_free (IdeXmlRngDefine *self)
   if (self->content != NULL)
     ide_xml_rng_define_unref (self->content);
 
-  if (self->content != NULL)
+  if (self->attributes != NULL)
     ide_xml_rng_define_unref (self->attributes);
 
-  if (self->content != NULL)
+  if (self->name_class != NULL)
     ide_xml_rng_define_unref (self->name_class);
 
   g_slice_free (IdeXmlRngDefine, self);
diff --git a/plugins/xml-pack/ide-xml-rng-parser.c b/plugins/xml-pack/ide-xml-rng-parser.c
index 6aaf957..335fc28 100644
--- a/plugins/xml-pack/ide-xml-rng-parser.c
+++ b/plugins/xml-pack/ide-xml-rng-parser.c
@@ -809,11 +809,14 @@ parse_value (IdeXmlRngParser *self,
              xmlNode         *node)
 {
   IdeXmlRngDefine *def = NULL;
+  guchar *name;
 
   g_assert (IDE_IS_XML_RNG_PARSER (self));
   g_assert (node != NULL);
 
-  /* TODO: not done for now */
+  /* TODO: datatype library part */
+  name = _strip (xmlNodeGetContent(node));
+  def = ide_xml_rng_define_new (node, self->current_def, name, IDE_XML_RNG_DEFINE_VALUE);
 
   return def;
 }
diff --git a/plugins/xml-pack/ide-xml-symbol-node.c b/plugins/xml-pack/ide-xml-symbol-node.c
index d93c9e6..e0c5809 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.c
+++ b/plugins/xml-pack/ide-xml-symbol-node.c
@@ -21,6 +21,12 @@
 
 #include "ide-xml-symbol-node.h"
 
+typedef struct _Attribute
+{
+  gchar *name;
+  gchar *value;
+} Attribute;
+
 typedef struct _NodeEntry
 {
   IdeXmlSymbolNode *node;
@@ -47,7 +53,7 @@ struct _IdeXmlSymbolNode
   gint                    nb_children;
   gint                    nb_internal_children;
   GFile                  *file;
-  gchar                 **attributes_names;
+  GArray                 *attributes;
   gchar                  *ns;
   IdeXmlSymbolNodeState   state;
   NodeRange               start_tag;
@@ -115,6 +121,7 @@ ide_xml_symbol_node_finalize (GObject *object)
   IdeXmlSymbolNode *self = (IdeXmlSymbolNode *)object;
 
   g_clear_pointer (&self->children, g_array_unref);
+  g_clear_pointer (&self->attributes, g_array_unref);
 
   g_clear_pointer (&self->element_name, g_free);
   g_clear_pointer (&self->value, g_free);
@@ -122,9 +129,6 @@ ide_xml_symbol_node_finalize (GObject *object)
   g_clear_object (&self->file);
   g_clear_object (&self->parent);
 
-  if (self->attributes_names != NULL)
-    g_strfreev (self->attributes_names);
-
   G_OBJECT_CLASS (ide_xml_symbol_node_parent_class)->finalize (object);
 }
 
@@ -661,23 +665,69 @@ ide_xml_symbol_node_compare_location (IdeXmlSymbolNode *ref_node,
 }
 
 void
-ide_xml_symbol_node_take_attributes_names (IdeXmlSymbolNode  *self,
-                                           gchar            **attributes_names)
+ide_xml_symbol_node_set_attributes (IdeXmlSymbolNode  *self,
+                                    const gchar      **attributes)
 {
+  Attribute attr;
+
   g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (self));
 
-  if (self->attributes_names != NULL)
-    g_strfreev (self->attributes_names);
+  g_clear_pointer (&self->attributes, g_array_unref);
+  if (attributes == NULL)
+    return;
 
-  self->attributes_names = attributes_names;
+  self->attributes = g_array_new (FALSE, FALSE, sizeof (Attribute));
+  while (attributes [0] != NULL)
+    {
+      attr.name = g_strdup (attributes [0]);
+      attr.value = (attributes [1] != NULL) ? g_strdup (attributes [1]) : NULL;
+      g_array_append_val (self->attributes, attr);
+      attributes += 2;
+    }
 }
 
-const gchar **
+gchar **
 ide_xml_symbol_node_get_attributes_names (IdeXmlSymbolNode  *self)
 {
+  Attribute *attr;
+  GPtrArray *ar_names;
+
+  g_return_val_if_fail (IDE_IS_XML_SYMBOL_NODE (self), NULL);
+
+  if (self->attributes == NULL)
+    return NULL;
+
+  ar_names = g_ptr_array_new ();
+  for (gint i = 0; i < self->attributes->len; ++i)
+    {
+      attr = &g_array_index (self->attributes, Attribute, i);
+      g_ptr_array_add (ar_names, g_strdup (attr->name));
+    }
+
+  g_ptr_array_add (ar_names, NULL);
+
+  return (gchar **)g_ptr_array_free (ar_names, FALSE);
+}
+
+const gchar *
+ide_xml_symbol_node_get_attribute_value (IdeXmlSymbolNode *self,
+                                         const gchar      *name)
+{
+  Attribute *attr;
+
   g_return_val_if_fail (IDE_IS_XML_SYMBOL_NODE (self), NULL);
 
-  return (const gchar **)self->attributes_names;
+  if (self->attributes == NULL || name == NULL)
+    return NULL;
+
+  for (gint i = 0; i < self->attributes->len; ++i)
+    {
+      attr = &g_array_index (self->attributes, Attribute, i);
+      if (ide_str_equal0 (name, attr->name))
+        return attr->value;
+    }
+
+  return NULL;
 }
 
 void
@@ -688,9 +738,9 @@ ide_xml_symbol_node_print (IdeXmlSymbolNode  *self,
                            gboolean           show_attributes)
 {
   g_autofree gchar *spacer;
-  gchar **attributes = self->attributes_names;
   guint n_children;
   IdeXmlSymbolNode *child;
+  Attribute *attr;
 
   g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (self));
 
@@ -704,12 +754,14 @@ ide_xml_symbol_node_print (IdeXmlSymbolNode  *self,
   printf ("%s%s state:%d ", spacer, self->element_name, self->state);
   print_node_ranges (self);
 
-  if (show_attributes && self->attributes_names != NULL)
-    while (*attributes != NULL)
-      {
-        printf ("%s%s\n", spacer, *attributes);
-        ++attributes;
-      }
+  if (show_attributes && self->attributes != NULL)
+    {
+      for (gint i = 0; i < self->attributes->len; ++i)
+        {
+          attr = &g_array_index (self->attributes, Attribute, i);
+          printf ("attr '%s':'%s'\n", attr->name, attr->value);
+        }
+    }
 
   if (show_value && self->value != NULL)
     printf ("%svalue:%s\n", spacer, self->value);
diff --git a/plugins/xml-pack/ide-xml-symbol-node.h b/plugins/xml-pack/ide-xml-symbol-node.h
index 9a15b80..acbd231 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.h
+++ b/plugins/xml-pack/ide-xml-symbol-node.h
@@ -112,9 +112,11 @@ void                              ide_xml_symbol_node_set_state
                                                                                      IdeXmlSymbolNodeState   
state);
 void                              ide_xml_symbol_node_set_value                     (IdeXmlSymbolNode       
*self,
                                                                                      const gchar            
*value);
-const gchar                     **ide_xml_symbol_node_get_attributes_names          (IdeXmlSymbolNode       
*self);
-void                              ide_xml_symbol_node_take_attributes_names         (IdeXmlSymbolNode       
*self,
-                                                                                     gchar                 
**attributes_names);
+gchar                           **ide_xml_symbol_node_get_attributes_names          (IdeXmlSymbolNode       
*self);
+const gchar                      *ide_xml_symbol_node_get_attribute_value           (IdeXmlSymbolNode       
*self,
+                                                                                     const gchar            
*name);
+void                              ide_xml_symbol_node_set_attributes                (IdeXmlSymbolNode       
*self,
+                                                                                     const gchar           
**attributes);
 
 G_END_DECLS
 
diff --git a/plugins/xml-pack/meson.build b/plugins/xml-pack/meson.build
index 593d244..7baa841 100644
--- a/plugins/xml-pack/meson.build
+++ b/plugins/xml-pack/meson.build
@@ -11,6 +11,8 @@ xml_pack_sources = [
   'ide-xml-analysis.h',
   'ide-xml-completion-attributes.c',
   'ide-xml-completion-attributes.h',
+  'ide-xml-completion-values.c',
+  'ide-xml-completion-values.h',
   'ide-xml-completion-provider.c',
   'ide-xml-completion-provider.h',
   'ide-xml-diagnostic-provider.c',


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