[gnome-builder/wip/slaf/xml-pack] xml-pack: get position details infos fron nodes tree



commit ea1e32fd6a24951915e8e615a092066313584f24
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Sun Jul 9 16:05:49 2017 +0200

    xml-pack: get position details infos fron nodes tree

 plugins/xml-pack/ide-xml-service.c |  198 +++++++++++++++++++++++++++++++---
 plugins/xml-pack/ide-xml-utils.c   |  208 ++++++++++++++++++++++++++++++++++++
 plugins/xml-pack/ide-xml-utils.h   |   33 ++++++
 3 files changed, 423 insertions(+), 16 deletions(-)
---
diff --git a/plugins/xml-pack/ide-xml-service.c b/plugins/xml-pack/ide-xml-service.c
index 631fc0f..4cde820 100644
--- a/plugins/xml-pack/ide-xml-service.c
+++ b/plugins/xml-pack/ide-xml-service.c
@@ -27,6 +27,7 @@
 #include "ide-xml-schema-cache-entry.h"
 #include "ide-xml-tree-builder.h"
 #include "ide-xml-types.h"
+#include "ide-xml-utils.h"
 
 #include "ide-xml-service.h"
 
@@ -626,6 +627,161 @@ position_state_free (PositionState *state)
   g_object_unref (state->buffer);
 }
 
+static inline gboolean
+skip_whitespaces (const gchar **cursor)
+{
+  const gchar *p = *cursor;
+  gunichar ch;
+
+  g_assert (cursor != NULL && *cursor != NULL);
+
+  while ((ch = g_utf8_get_char (*cursor)) && g_unichar_isspace (ch))
+    *cursor = g_utf8_next_char (*cursor);
+
+  return (p != *cursor);
+}
+
+static inline void
+skip_all_name (const gchar **cursor)
+{
+  gunichar ch;
+
+  g_assert (cursor != NULL && *cursor != NULL);
+
+  while ((ch = g_utf8_get_char (*cursor)) && !g_unichar_isspace (ch))
+    *cursor = g_utf8_next_char (*cursor);
+}
+
+static IdeXmlPositionDetail
+get_detail (IdeXmlSymbolNode  *node,
+            const gchar       *prefix,
+            gunichar           next_ch,
+            gchar            **name,
+            gchar            **value,
+            gchar             *quote)
+{
+  IdeXmlPositionDetail detail;
+  const gchar *cursor, *start;
+  const gchar *name_start;
+  gsize name_size;
+  gboolean has_spaces = FALSE;
+
+  g_assert (IDE_IS_XML_SYMBOL_NODE (node));
+  g_assert (prefix != NULL);
+  g_assert (value != NULL);
+
+  *name = NULL;
+  *value = NULL;
+  *quote = 0;
+
+  cursor = prefix;
+  detail =  IDE_XML_POSITION_DETAIL_IN_NAME;
+  if (!ide_xml_utils_skip_element_name (&cursor))
+    return IDE_XML_POSITION_DETAIL_NONE;
+
+  if (*cursor == 0)
+    {
+      if (!g_unichar_isspace (next_ch) && next_ch != '<' && next_ch != '>')
+        return IDE_XML_POSITION_DETAIL_NONE;
+      else
+        {
+          *name = g_strdup (prefix);
+          return detail;
+        }
+    }
+
+  detail =  IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_NAME;
+  /* Whitespaces after the element name */
+  skip_whitespaces (&cursor);
+  if (*cursor == 0)
+    return detail;
+
+  while (TRUE)
+    {
+      *quote = 0;
+      start = cursor;
+      /* Attribute name */
+      if (!ide_xml_utils_skip_attribute_name (&cursor))
+        continue;
+
+      if (*cursor == 0)
+        {
+          if (!g_unichar_isspace (next_ch) && next_ch != '=')
+            return IDE_XML_POSITION_DETAIL_NONE;
+
+          *name = g_strndup (start, cursor - start);
+          return detail;
+        }
+
+      name_start = start;
+      name_size = cursor - start;
+      /* Whitespaces between the name and the = */
+      skip_whitespaces (&cursor);
+      if (*cursor == 0)
+        return detail;
+
+      if (*cursor != '=')
+        continue;
+      else
+        cursor++;
+
+      /* Whitespaces after the = */
+      /* TODO: at this point we need to add quoted around the value */
+      detail =  IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_VALUE;
+      skip_whitespaces (&cursor);
+      if (*cursor == 0)
+        {
+          *name = g_strndup (name_start, name_size);
+          return detail;
+        }
+
+      *quote = *cursor;
+      start = ++cursor;
+      if (*quote != '"' && *quote != '\'')
+        {
+          *quote = 0;
+          if (!g_unichar_isspace(*(cursor -1)))
+            {
+              skip_all_name (&cursor);
+              if (*cursor == 0)
+                return IDE_XML_POSITION_DETAIL_NONE;
+
+              skip_whitespaces (&cursor);
+              if (*cursor == 0)
+                return IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_NAME;
+            }
+
+          continue;
+        }
+
+      /* Attribute value */
+      if (!ide_xml_utils_skip_attribute_value (&cursor, *quote))
+        {
+          *name = g_strndup (name_start, name_size);
+          *value = g_strndup (start, cursor - start);
+          return detail;
+        }
+
+      detail =  IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_NAME;
+      /* Whitespaces after the attribute value */
+      if (skip_whitespaces (&cursor))
+        has_spaces = TRUE;
+
+      if (*cursor == 0)
+        {
+          *quote = 0;
+          return (has_spaces) ? IDE_XML_POSITION_DETAIL_IN_ATTRIBUTE_NAME : IDE_XML_POSITION_DETAIL_NONE;
+        }
+
+      if (!has_spaces)
+        {
+          skip_all_name (&cursor);
+          if (*cursor == 0)
+            return IDE_XML_POSITION_DETAIL_NONE;
+        }
+    };
+}
+
 static IdeXmlPosition *
 get_position (IdeXmlService   *self,
               IdeXmlAnalysis  *analysis,
@@ -635,7 +791,8 @@ get_position (IdeXmlService   *self,
 {
   IdeXmlPosition *position;
   IdeXmlSymbolNode *root_node;
-  IdeXmlSymbolNode *current_node, *child_node, *candidate_node;
+  IdeXmlSymbolNode *current_node, *child_node;
+  IdeXmlSymbolNode *candidate_node = NULL;
   IdeXmlSymbolNode *previous_node = NULL;
   IdeXmlSymbolNode *previous_sibling_node = NULL;
   IdeXmlSymbolNode *next_sibling_node = NULL;
@@ -643,11 +800,15 @@ get_position (IdeXmlService   *self,
   IdeXmlPositionKind candidate_kind;
   IdeXmlPositionDetail detail = IDE_XML_POSITION_DETAIL_NONE;
   g_autofree gchar *prefix = NULL;
+  g_autofree gchar *detail_name = NULL;
+  g_autofree gchar *detail_value = NULL;
   GtkTextIter start, end;
+  gunichar next_ch = 0;
   gint start_line, start_line_offset;
   guint n_children;
   gint child_pos = -1;
   gint n = 0;
+  gchar quote = 0;
   gboolean has_prefix = FALSE;
 
   g_assert (IDE_IS_XML_SERVICE (self));
@@ -672,14 +833,12 @@ loop:
             case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_IN_START_TAG:
               candidate_node = child_node;
               candidate_kind = IDE_XML_POSITION_KIND_IN_START_TAG;
-              detail = IDE_XML_POSITION_DETAIL_IN_NAME;
               has_prefix = TRUE;
               goto result;
 
             case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_IN_END_TAG:
               candidate_node = child_node;
               candidate_kind = IDE_XML_POSITION_KIND_IN_END_TAG;
-              detail = IDE_XML_POSITION_DETAIL_IN_NAME;
               has_prefix = TRUE;
               goto result;
 
@@ -702,7 +861,8 @@ loop:
               break;
 
             case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_IN_CONTENT:
-              current_node = previous_node = child_node;
+              candidate_node = current_node = previous_node = child_node;
+              candidate_kind = IDE_XML_POSITION_KIND_IN_CONTENT;
               goto loop;
 
             case IDE_XML_POSITION_KIND_UNKNOW:
@@ -719,16 +879,16 @@ result:
       candidate_node = root_node;
       candidate_kind = IDE_XML_POSITION_KIND_IN_CONTENT;
     }
-  else if (candidate_kind == IDE_XML_POSITION_KIND_IN_CONTENT &&
-           previous_node != NULL &&
-           ide_xml_symbol_node_get_state (previous_node) == IDE_XML_SYMBOL_NODE_STATE_NOT_CLOSED)
+  else if (candidate_kind == IDE_XML_POSITION_KIND_IN_CONTENT)
     {
-      candidate_node = previous_node;
-      /* TODO: fetch detail and more infos */
-      /* TODO: detect the IN_END_TAG case */
-      candidate_kind = IDE_XML_POSITION_KIND_IN_START_TAG;
-      detail = IDE_XML_POSITION_DETAIL_IN_NAME;
-      has_prefix = TRUE;
+      if (previous_node != NULL &&
+          ide_xml_symbol_node_get_state (previous_node) == IDE_XML_SYMBOL_NODE_STATE_NOT_CLOSED)
+        {
+          candidate_node = previous_node;
+          /* TODO: detect the IN_END_TAG case */
+          candidate_kind = IDE_XML_POSITION_KIND_IN_START_TAG;
+          has_prefix = TRUE;
+        }
     }
 
   if (has_prefix)
@@ -740,13 +900,19 @@ result:
       if (gtk_text_iter_get_char (&start) == '<')
         gtk_text_iter_forward_char (&start);
 
+      next_ch = gtk_text_iter_get_char (&end);
       if (!gtk_text_iter_equal (&start, &end))
-        prefix = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+        {
+          prefix = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+          detail = get_detail (candidate_node, prefix, next_ch, &detail_name, &detail_value, &quote);
+        }
+      else
+        detail = IDE_XML_POSITION_DETAIL_IN_NAME;
     }
 
   if (candidate_kind == IDE_XML_POSITION_KIND_IN_CONTENT)
     {
-      position = ide_xml_position_new (candidate_node, prefix, candidate_kind, detail);
+      position = ide_xml_position_new (candidate_node, prefix, candidate_kind, detail, detail_name, 
detail_value, quote);
       ide_xml_position_set_analysis (position, analysis);
       ide_xml_position_set_child_pos (position, child_pos);
     }
@@ -756,7 +922,7 @@ result:
       child_node = candidate_node;
       candidate_node = ide_xml_symbol_node_get_parent (child_node);
 
-      position = ide_xml_position_new (candidate_node, prefix, candidate_kind, detail);
+      position = ide_xml_position_new (candidate_node, prefix, candidate_kind, detail, detail_name, 
detail_value, quote);
       ide_xml_position_set_analysis (position, analysis);
       ide_xml_position_set_child_node (position, child_node);
     }
diff --git a/plugins/xml-pack/ide-xml-utils.c b/plugins/xml-pack/ide-xml-utils.c
new file mode 100644
index 0000000..b76ad6d
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-utils.c
@@ -0,0 +1,208 @@
+/* ide-xml-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-utils.h"
+
+static inline gboolean
+is_name_start_char (gunichar ch)
+{
+  return ((ch >= 'A' && ch <= 'Z') ||
+          (ch >= 'a' && ch <= 'z') ||
+          ch == ':' ||
+          ch == '_' ||
+          (ch >= 0xC0 && ch <= 0xD6) ||
+          (ch >= 0xD8 && ch <= 0xF6) ||
+          (ch >= 0xF8 && ch <= 0x2FF) ||
+          (ch >= 0x370 && ch <= 0x37D) ||
+          (ch >= 0x37F && ch <= 0x1FFF) ||
+          (ch >= 0x200C && ch <= 0x200D) ||
+          (ch >= 0x2070 && ch <= 0x218F) ||
+          (ch >= 0x2C00 && ch <= 0x2FEF) ||
+          (ch >= 0x3001 && ch <= 0xD7FF) ||
+          (ch >= 0xF900 && ch <= 0xFDCF) ||
+          (ch >= 0xFDF0 && ch <= 0xFFFD) ||
+          (ch >= 0x10000 && ch <= 0xEFFFF));
+}
+
+static inline gboolean
+is_name_char (gunichar ch)
+{
+  return (is_name_start_char (ch) ||
+          ch == '-' ||
+          ch == '.' ||
+          (ch >= '0' && ch <= '9') ||
+          ch == 0xB7 ||
+          (ch >= 0x300 && ch <= 0x36F) ||
+          (ch >= 0x203F && ch <= 0x2040));
+}
+
+/* Return TRUE if we found spaces */
+static inline gboolean
+skip_whitespaces (const gchar **cursor)
+{
+  const gchar *p = *cursor;
+  gunichar ch;
+
+  g_assert (cursor != NULL && *cursor != NULL);
+
+  while ((ch = g_utf8_get_char (*cursor)) && g_unichar_isspace (ch))
+    *cursor = g_utf8_next_char (*cursor);
+
+  return (p != *cursor);
+}
+
+static void
+jump_to_next_attribute (const gchar **cursor)
+{
+  const gchar *p = *cursor;
+  gunichar ch;
+  gchar term;
+  gboolean has_spaces = FALSE;
+
+  while ((ch = g_utf8_get_char (p)))
+    {
+      if (g_unichar_isspace (ch))
+        {
+          skip_whitespaces (&p);
+          break;
+        }
+
+      if (ch == '=')
+        break;
+
+      p = g_utf8_next_char (p);
+    }
+
+  if (ch != '=')
+    {
+      *cursor = p;
+      return;
+    }
+
+  p++;
+  if (skip_whitespaces (&p))
+    has_spaces = TRUE;
+
+  if (ch == '"' || ch == '\'')
+    {
+      term = ch;
+      while ((ch = g_utf8_get_char (p)) && ch != term)
+        p = g_utf8_next_char (p);
+
+      if (ch == term)
+        {
+          p++;
+          skip_whitespaces (&p);
+        }
+    }
+  else if (!has_spaces)
+    {
+      while ((ch = g_utf8_get_char (p)) && !g_unichar_isspace (ch))
+        p = g_utf8_next_char (p);
+    }
+
+  *cursor = p;
+}
+
+/* Return FALSE if not valid */
+gboolean
+ide_xml_utils_skip_element_name (const gchar **cursor)
+{
+  const gchar *p = *cursor;
+  gunichar ch;
+
+  g_return_val_if_fail (cursor != NULL, FALSE);
+
+  if (!(ch = g_utf8_get_char (p)))
+    return TRUE;
+
+  if (!is_name_start_char (ch))
+    return (g_unichar_isspace (ch));
+
+  p = g_utf8_next_char (p);
+  while ((ch = g_utf8_get_char (p)))
+    {
+      if (!is_name_char (ch))
+        {
+          *cursor = p;
+          return g_unichar_isspace (ch);
+        }
+
+      p = g_utf8_next_char (p);
+    }
+
+  *cursor = p;
+  return TRUE;
+}
+
+/* Return FALSE at the end of the string */
+gboolean
+ide_xml_utils_skip_attribute_value (const gchar **cursor,
+                                    gchar         term)
+{
+  const gchar *p = *cursor;
+  gunichar ch;
+
+  g_return_val_if_fail (cursor != NULL && *cursor != NULL, FALSE);
+
+  while ((ch = g_utf8_get_char (p)) && ch != term)
+    p = g_utf8_next_char (p);
+
+  if (ch == term)
+    p++;
+
+  *cursor = p;
+  return (ch != 0);
+}
+
+/* Return FALSE if not valid */
+gboolean
+ide_xml_utils_skip_attribute_name (const gchar **cursor)
+{
+  const gchar *p = *cursor;
+  gunichar ch;
+
+  g_return_val_if_fail (cursor != NULL, FALSE);
+
+  if (!(ch = g_utf8_get_char (p)))
+    return TRUE;
+
+  if (!is_name_start_char (ch))
+    return (g_unichar_isspace (ch));
+
+  p = g_utf8_next_char (p);
+  while ((ch = g_utf8_get_char (p)))
+    {
+      if (!is_name_char (ch))
+        {
+          *cursor = p;
+          if (g_unichar_isspace (ch) || ch == '=')
+            return TRUE;
+          else
+            {
+              jump_to_next_attribute (cursor);
+              return FALSE;
+            }
+        }
+
+      p = g_utf8_next_char (p);
+    }
+
+  *cursor = p;
+  return TRUE;
+}
diff --git a/plugins/xml-pack/ide-xml-utils.h b/plugins/xml-pack/ide-xml-utils.h
new file mode 100644
index 0000000..c027c83
--- /dev/null
+++ b/plugins/xml-pack/ide-xml-utils.h
@@ -0,0 +1,33 @@
+/* ide-xml-utils.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_UTILS_H
+#define IDE_XML_UTILS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean      ide_xml_utils_skip_attribute_name    (const gchar **cursor);
+gboolean      ide_xml_utils_skip_attribute_value   (const gchar **cursor,
+                                                    gchar         term);
+gboolean      ide_xml_utils_skip_element_name      (const gchar **cursor);
+
+G_END_DECLS
+
+#endif /* IDE_XML_UTILS_H */


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