[gnome-builder] highlighter: Added xml highlighter used for highlighting matching tags



commit 96000f81f9f00add85f1fdd42269c7ac01a4beee
Author: Dimitris Zenios <dimitris zenios gmail com>
Date:   Tue May 12 00:48:07 2015 +0300

    highlighter: Added xml highlighter used for highlighting matching tags
    
    https://bugzilla.gnome.org/show_bug.cgi?id=746990

 data/style-schemes/builder.xml   |    1 +
 libide/Makefile.am               |    2 +
 libide/xml/ide-xml-highlighter.c |  241 ++++++++++++++++++++++++++++++++++++++
 libide/xml/ide-xml-highlighter.h |   33 +++++
 libide/xml/ide-xml-language.c    |   29 ++++-
 5 files changed, 303 insertions(+), 3 deletions(-)
---
diff --git a/data/style-schemes/builder.xml b/data/style-schemes/builder.xml
index c8bb140..08a9205 100644
--- a/data/style-schemes/builder.xml
+++ b/data/style-schemes/builder.xml
@@ -138,6 +138,7 @@
 
   <style name="xml:tags"                    foreground="chameleon3"/>
   <style name="xml:namespace"               bold="true"/>
+  <style name="xml:tag-match"               underline="true"/>
 
   <style name="js:object"                   foreground="chameleon3" bold="true"/>
   <style name="js:constructors"             foreground="pink1"/>
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 74c0cc4..fcaf482 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -222,6 +222,8 @@ libide_1_0_la_public_sources = \
        xml/ide-xml-indenter.h \
        xml/ide-xml-language.c \
        xml/ide-xml-language.h \
+       xml/ide-xml-highlighter.c \
+       xml/ide-xml-highlighter.h \
        ide-source-map.c \
        ide-source-map.h \
        ide-thread-pool.c \
diff --git a/libide/xml/ide-xml-highlighter.c b/libide/xml/ide-xml-highlighter.c
new file mode 100644
index 0000000..3c523c7
--- /dev/null
+++ b/libide/xml/ide-xml-highlighter.c
@@ -0,0 +1,241 @@
+/* ide-xml-highlighter.c
+ *
+ * Copyright (C) 2015 Dimitris Zenios <dimitris zenios gmail com>
+ *
+ * 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 <glib/gi18n.h>
+
+#include "ide-xml-highlighter.h"
+#include "ide-context.h"
+#include "ide-buffer.h"
+#include "ide-xml.h"
+#include "ide-highlight-engine.h"
+
+#define HIGHLIGH_TIMEOUT_MSEC    250
+#define XML_TAG_MATCH_STYLE_NAME "xml:tag-match"
+
+struct _IdeXmlHighlighter
+{
+  IdeHighlighter  parent_instance;
+
+  gboolean        has_tags;
+  guint           highlight_timeout;
+  GtkTextIter     iter;
+  IdeBuffer      *buffer;
+};
+
+G_DEFINE_TYPE (IdeXmlHighlighter, ide_xml_highlighter, IDE_TYPE_HIGHLIGHTER)
+
+static gboolean
+ide_xml_highlighter_highlight_timeout_handler (gpointer data)
+{
+  IdeXmlHighlighter *self = data;
+  IdeHighlightEngine *engine;
+  GtkTextTag *tag;
+  GtkTextIter start;
+  GtkTextIter end;
+  GtkTextBuffer *buffer;
+
+  g_assert (IDE_IS_XML_HIGHLIGHTER (self));
+
+  engine = ide_highlighter_get_highlight_engine (IDE_HIGHLIGHTER (self));
+  tag = ide_highlight_engine_get_style (engine, XML_TAG_MATCH_STYLE_NAME);
+
+  buffer = GTK_TEXT_BUFFER (self->buffer);
+
+  /*
+   * Clear previous tags.We could save the previous
+   * iters and clear only those locations but for
+   * now this should be ok
+   */
+  if (self->has_tags)
+    {
+      gtk_text_buffer_get_start_iter (buffer, &start);
+      gtk_text_buffer_get_end_iter (buffer, &end);
+      gtk_text_buffer_remove_tag (buffer,tag,&start,&end);
+
+      self->has_tags = FALSE;
+    }
+
+
+  if (ide_xml_in_element (&self->iter) && ide_xml_get_current_element (&self->iter,
+                                                                       &start,
+                                                                       &end))
+    {
+      GtkTextIter next_start;
+      GtkTextIter next_end;
+      IdeXmlElementTagType tag_type = ide_xml_get_element_tag_type (&start,
+                                                                    &end);
+
+      if ((tag_type == IDE_XML_ELEMENT_TAG_START &&
+          ide_xml_find_closing_element (&start,&end,
+                                      &next_start,&next_end)) ||
+          (tag_type == IDE_XML_ELEMENT_TAG_END &&
+          ide_xml_find_opening_element (&start,&end,
+                                      &next_start,&next_end)) ||
+          tag_type == IDE_XML_ELEMENT_TAG_START_END)
+        {
+
+          /*
+           * All iters point to the begining of < char and the
+           * beginning of > char.In our case we want to highlight everything that is
+           * between those two chars.This is the reason we move one char forward
+           * from the start iter
+           */
+          gtk_text_iter_forward_char (&start);
+          gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (buffer),
+                                     tag,
+                                     &start,
+                                     &end);
+
+          if (tag_type != IDE_XML_ELEMENT_TAG_START_END)
+            {
+              gtk_text_iter_forward_char (&next_start);
+              gtk_text_buffer_apply_tag (GTK_TEXT_BUFFER (buffer),
+                                         tag,
+                                         &next_start,
+                                         &next_end);
+            }
+
+          self->has_tags = TRUE;
+        }
+    }
+
+  self->highlight_timeout = 0;
+  return FALSE;
+}
+
+static void
+ide_xml_highlighter_cursor_moved_cb (GtkTextBuffer     *buffer,
+                                     GtkTextIter       *iter,
+                                     IdeXmlHighlighter *self)
+{
+  g_assert (IDE_IS_HIGHLIGHTER (self));
+
+  if (self->highlight_timeout != 0)
+    {
+      g_source_remove (self->highlight_timeout);
+      self->highlight_timeout = 0;
+    }
+
+  self->iter = *iter;
+  self->highlight_timeout = g_timeout_add (HIGHLIGH_TIMEOUT_MSEC,
+                                           ide_xml_highlighter_highlight_timeout_handler,
+                                           self);
+}
+
+
+static void
+ide_xml_highlighter_set_buffer (IdeXmlHighlighter *highlighter,
+                                IdeBuffer         *buffer)
+{
+  IdeXmlHighlighter *self = (IdeXmlHighlighter *)highlighter;
+
+  g_assert (IDE_IS_HIGHLIGHTER (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  if (self->buffer != buffer)
+    {
+      if (self->buffer != NULL)
+        {
+          g_signal_handlers_disconnect_by_func (self->buffer,
+                                                G_CALLBACK (ide_xml_highlighter_cursor_moved_cb),
+                                                self);
+          ide_clear_weak_pointer (&self->buffer);
+        }
+
+      if (buffer != NULL)
+        {
+          g_signal_connect (buffer,
+                            "cursor-moved",
+                            G_CALLBACK (ide_xml_highlighter_cursor_moved_cb),
+                            self);
+          ide_set_weak_pointer (&self->buffer, buffer);
+        }
+
+    }
+}
+
+static void
+ide_xml_highlighter_on_buffer_set (IdeHighlighter *self,
+                                   GParamSpec     *pspec,
+                                   IdeBuffer      *buffer)
+{
+  IdeXmlHighlighter *highlighter = IDE_XML_HIGHLIGHTER (self);
+
+  g_assert (IDE_IS_XML_HIGHLIGHTER (highlighter));
+
+  ide_xml_highlighter_set_buffer (highlighter, buffer);
+}
+
+static void
+ide_xml_highlighter_on_highlight_engine_set (IdeHighlighter  *self,
+                                             GParamSpec      *pspec,
+                                             gpointer        *data)
+{
+  IdeXmlHighlighter *highlighter = IDE_XML_HIGHLIGHTER (self);
+  IdeHighlightEngine *engine = ide_highlighter_get_highlight_engine (self);
+
+  g_assert (IDE_IS_XML_HIGHLIGHTER (highlighter));
+  g_assert (engine != NULL);
+
+  ide_xml_highlighter_set_buffer (highlighter, ide_highlight_engine_get_buffer (engine));
+  g_signal_connect_object (engine,
+                           "notify::buffer",
+                           G_CALLBACK (ide_xml_highlighter_on_buffer_set),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+ide_xml_highlighter_constructed (GObject *object)
+{
+  IdeXmlHighlighter *self = (IdeXmlHighlighter *)object;
+
+  g_signal_connect (self,
+                    "notify::highlight-engine",
+                    G_CALLBACK (ide_xml_highlighter_on_highlight_engine_set),
+                    NULL);
+}
+
+static void
+ide_xml_highlighter_engine_dispose (GObject *object)
+{
+  IdeXmlHighlighter *self = (IdeXmlHighlighter *)object;
+
+  if (self->highlight_timeout != 0)
+    {
+      g_source_remove (self->highlight_timeout);
+      self->highlight_timeout = 0;
+    }
+  ide_clear_weak_pointer (&self->buffer);
+
+  G_OBJECT_CLASS (ide_xml_highlighter_parent_class)->dispose (object);
+}
+
+static void
+ide_xml_highlighter_class_init (IdeXmlHighlighterClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_xml_highlighter_engine_dispose;
+  object_class->constructed = ide_xml_highlighter_constructed;
+}
+
+static void
+ide_xml_highlighter_init (IdeXmlHighlighter *self)
+{
+}
diff --git a/libide/xml/ide-xml-highlighter.h b/libide/xml/ide-xml-highlighter.h
new file mode 100644
index 0000000..ce45c7f
--- /dev/null
+++ b/libide/xml/ide-xml-highlighter.h
@@ -0,0 +1,33 @@
+/* ide-xml-highlighter.h
+ *
+ * Copyright (C) 2015 Dimitris Zenios <dimitris zenios gmail com>
+ *
+ * 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_HIGHLIGHTER_H
+#define IDE_XML_HIGHLIGHTER_H
+
+#include "ide-highlighter.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_XML_HIGHLIGHTER (ide_xml_highlighter_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeXmlHighlighter, ide_xml_highlighter,
+                      IDE, XML_HIGHLIGHTER, IdeHighlighter)
+
+G_END_DECLS
+
+#endif /* IDE_XML_HIGHLIGHTER_H */
diff --git a/libide/xml/ide-xml-language.c b/libide/xml/ide-xml-language.c
index 5c0173f..0695539 100644
--- a/libide/xml/ide-xml-language.c
+++ b/libide/xml/ide-xml-language.c
@@ -18,11 +18,14 @@
 
 #include "ide-xml-language.h"
 #include "ide-xml-indenter.h"
+#include "ide-xml-highlighter.h"
 
 struct _IdeXmlLanguage
 {
-  IdeLanguage     parent_instance;
-  IdeXmlIndenter *indenter;
+  IdeLanguage        parent_instance;
+
+  IdeXmlIndenter    *indenter;
+  IdeXmlHighlighter *highlighter;
 };
 
 static void initable_iface_init (GInitableIface *iface);
@@ -51,6 +54,26 @@ ide_xml_language_get_indenter (IdeLanguage *language)
   return IDE_INDENTER (self->indenter);
 }
 
+static IdeHighlighter *
+ide_xml_language_get_highlighter (IdeLanguage *language)
+{
+  IdeXmlLanguage *self = (IdeXmlLanguage *)language;
+
+  g_return_val_if_fail (IDE_IS_XML_LANGUAGE (self), NULL);
+
+  if (!self->highlighter)
+    {
+      IdeContext *context;
+
+      context = ide_object_get_context (IDE_OBJECT (language));
+      self->highlighter = g_object_new (IDE_TYPE_XML_HIGHLIGHTER,
+                                        "context", context,
+                                        NULL);
+    }
+
+  return IDE_HIGHLIGHTER (self->highlighter);
+}
+
 static void
 ide_xml_language_finalize (GObject *object)
 {
@@ -68,7 +91,7 @@ ide_xml_language_class_init (IdeXmlLanguageClass *klass)
   IdeLanguageClass *language_class = IDE_LANGUAGE_CLASS (klass);
 
   object_class->finalize = ide_xml_language_finalize;
-
+  language_class->get_highlighter = ide_xml_language_get_highlighter;
   language_class->get_indenter = ide_xml_language_get_indenter;
 }
 


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