[gnome-builder/wip/slaf/xml-pack: 252/254] xml-pack: tweak the tree optionality



commit b46bfd5894da73e89bfdde0150239913b9980c60
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Wed Jul 12 00:58:01 2017 +0200

    xml-pack: tweak the tree optionality
    
    We need to adjust the optionality on some
    rng strcutures when we have existing attributes
    in the current node.
    
    The parser now use a two phases algorithm:
    1. We check the rng attribute position in the node and
       propagate a mandatory field. this way we can transform for example
       an Optional into a Group.
    
    2. We walk the tree to add the matching attributes.
    
    We also introduce a filter to remove duplicates and sort
    the proposals by alphabetical order.

 plugins/xml-pack/ide-xml-completion-attributes.c |  159 +++++++++++++++++++--
 plugins/xml-pack/ide-xml-rng-define.c            |    1 +
 plugins/xml-pack/ide-xml-rng-define.h            |    5 +
 3 files changed, 149 insertions(+), 16 deletions(-)
---
diff --git a/plugins/xml-pack/ide-xml-completion-attributes.c 
b/plugins/xml-pack/ide-xml-completion-attributes.c
index 820991b..5163af3 100644
--- a/plugins/xml-pack/ide-xml-completion-attributes.c
+++ b/plugins/xml-pack/ide-xml-completion-attributes.c
@@ -24,6 +24,7 @@ typedef struct _MatchingState
 {
   IdeXmlSymbolNode *node;
   IdeXmlRngDefine  *define;
+  IdeXmlRngDefine  *orig_define;
   GPtrArray        *node_attr;
   GPtrArray        *match_children;
 
@@ -98,6 +99,7 @@ matching_state_new (IdeXmlRngDefine  *define,
   state = g_slice_new0 (MatchingState);
 
   state->define = define;
+  state->orig_define = define;
   state->node = node;
 
   state->node_attr = g_ptr_array_new_with_free_func (g_free);
@@ -121,7 +123,6 @@ process_attribute (MatchingState *state)
   GPtrArray *match_children;
   MatchItem *item;
   const gchar *name;
-  const gchar *attr;
 
   g_assert (state->define->type == IDE_XML_RNG_DEFINE_ATTRIBUTE);
 
@@ -131,19 +132,7 @@ process_attribute (MatchingState *state)
   if (ide_str_empty0 (name))
     return match_children;
 
-  for (gint i = 0; i < state->node_attr->len; i++)
-    {
-      attr = g_ptr_array_index (state->node_attr, i);
-      if (ide_str_equal0 (name, attr))
-        {
-          item = match_item_new (name, i, state->is_optional);
-          g_ptr_array_add (match_children, item);
-
-          return match_children;
-        }
-    }
-
-  item = match_item_new (name, -1, state->is_optional);
+  item = match_item_new (name, state->define->pos, state->is_optional);
   g_ptr_array_add (match_children, item);
 
   return match_children;
@@ -344,7 +333,9 @@ process_matching_state (MatchingState   *state,
     case IDE_XML_RNG_DEFINE_ONEORMORE:
     case IDE_XML_RNG_DEFINE_OPTIONAL:
       old_optional = state->is_optional;
-      if (type == IDE_XML_RNG_DEFINE_ZEROORMORE || type == IDE_XML_RNG_DEFINE_OPTIONAL)
+      if (define->is_mandatory)
+        state->is_optional = FALSE;
+      else if (type == IDE_XML_RNG_DEFINE_ZEROORMORE || type == IDE_XML_RNG_DEFINE_OPTIONAL)
         state->is_optional = TRUE;
 
       match_children = process_group (state);
@@ -413,7 +404,18 @@ compare_attribute_names (gpointer a,
   return ide_str_equal0 (match->name, attr_name);
 }
 
-/* Remove completion items already in the current node */
+static gint
+alphabetical_sort_func (gpointer *a,
+                        gpointer *b)
+{
+  MatchItem *match_a = (MatchItem *)*a;
+  MatchItem *match_b = (MatchItem *)*b;
+
+  return g_ascii_strcasecmp (match_b->name, match_a->name);
+}
+
+/* Remove completion items already in the current node and
+ * filter the list by alphabetical order. */
 static void
 match_children_filter (GPtrArray *match_children,
                        GPtrArray *node_attributes)
@@ -433,6 +435,128 @@ match_children_filter (GPtrArray *match_children,
       else
         ++i;
     }
+
+  g_ptr_array_sort (match_children, (GCompareFunc)alphabetical_sort_func);
+}
+
+static void
+propagate_mandatory (MatchingState *state)
+{
+  IdeXmlRngDefine *define = state->define;
+
+  g_assert (state != NULL);
+
+  while (define != state->orig_define)
+    {
+      if (define->type == IDE_XML_RNG_DEFINE_OPTIONAL || define->type == IDE_XML_RNG_DEFINE_ZEROORMORE)
+        define->is_mandatory = TRUE;
+
+      define = define->parent;
+    }
+}
+
+static void
+set_position (MatchingState *state)
+{
+  const gchar *attribute;
+  guint index;
+
+  g_assert (state != NULL);
+
+  if (NULL == (attribute = (const gchar *)state->define->name) ||
+      !g_ptr_array_find_with_equal_func (state->node_attr, attribute, (GEqualFunc)g_str_equal, &index))
+    {
+      index = -1;
+    }
+  else
+    {
+      propagate_mandatory (state);
+    }
+
+  state->define->pos = index;
+}
+
+static void
+set_attributes_position (MatchingState   *state,
+                         IdeXmlRngDefine *define)
+{
+  IdeXmlRngDefine *child_define;
+  IdeXmlRngDefine *old_define;
+  IdeXmlRngDefineType type;
+
+  g_assert (state != NULL);
+  g_assert (define != NULL);
+
+  old_define = state->define;
+  state->define = define;
+
+  /* Reset the value from a previous completion */
+  define->is_mandatory = FALSE;
+
+  if (state->is_initial_state)
+    {
+      state->is_initial_state = FALSE;
+      type = IDE_XML_RNG_DEFINE_ATTRIBUTES_GROUP;
+    }
+  else
+    type = define->type;
+
+  switch (type)
+    {
+    case IDE_XML_RNG_DEFINE_ATTRIBUTE:
+      set_position (state);
+      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_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:
+      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:
+      set_attributes_position (state, define->content);
+      break;
+
+    case IDE_XML_RNG_DEFINE_INTERLEAVE:
+    case IDE_XML_RNG_DEFINE_GROUP:
+    case IDE_XML_RNG_DEFINE_CHOICE:
+    case IDE_XML_RNG_DEFINE_ZEROORMORE:
+    case IDE_XML_RNG_DEFINE_ONEORMORE:
+    case IDE_XML_RNG_DEFINE_OPTIONAL:
+      child_define = state->define->content;
+      while (child_define != NULL)
+        {
+          set_attributes_position (state, child_define);
+          child_define = child_define->next;
+        }
+
+      break;
+
+    case IDE_XML_RNG_DEFINE_ATTRIBUTES_GROUP:
+      child_define = state->define->attributes;
+      while (child_define != NULL)
+        {
+          set_attributes_position (state, child_define);
+          child_define = child_define->next;
+        }
+
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  state->define = old_define;
 }
 
 /* Return an array of MatchItem */
@@ -450,6 +574,9 @@ ide_xml_completion_attributes_get_matches (IdeXmlRngDefine  *define,
     return NULL;
 
   initial_state = create_initial_matching_state (define, node);
+  set_attributes_position (initial_state, define);
+
+  initial_state->is_initial_state = TRUE;
   match_children = process_matching_state (initial_state, define);
   match_children_filter (match_children, initial_state->node_attr);
 
diff --git a/plugins/xml-pack/ide-xml-rng-define.c b/plugins/xml-pack/ide-xml-rng-define.c
index 2e64b17..a8f0f5d 100644
--- a/plugins/xml-pack/ide-xml-rng-define.c
+++ b/plugins/xml-pack/ide-xml-rng-define.c
@@ -39,6 +39,7 @@ static gchar *type_names [] =
   "optional",
   "choice",
   "group",
+  "attribute group",
   "interleave",
   "attribute",
   "start",
diff --git a/plugins/xml-pack/ide-xml-rng-define.h b/plugins/xml-pack/ide-xml-rng-define.h
index 2d08574..8cb0900 100644
--- a/plugins/xml-pack/ide-xml-rng-define.h
+++ b/plugins/xml-pack/ide-xml-rng-define.h
@@ -71,8 +71,13 @@ struct _IdeXmlRngDefine
   IdeXmlRngDefineType  type;
 
   gint16               depth;
+  gint                 pos;
+
   guint                is_external_ref : 1;
   guint                is_ref_simplified : 1;
+
+  /* This field is relevant only for the current completion */
+  guint                is_mandatory : 1;
 };
 
 IdeXmlRngDefine     *ide_xml_rng_define_new                 (xmlNode             *node,


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