[gnome-builder] ctags: Implement a generic ctags highlighter



commit e05c5381d23b458757b42bcfc46daa7e657117f2
Author: Dimitris Zenios <dimitris zenios gmail com>
Date:   Fri May 22 01:13:50 2015 +0300

    ctags: Implement a generic ctags highlighter

 libide/Makefile.am                   |    2 +
 libide/ctags/ide-ctags-highlighter.c |  232 ++++++++++++++++++++++++++++++++++
 libide/ctags/ide-ctags-highlighter.h |   41 ++++++
 libide/ctags/ide-ctags-service.c     |   23 ++++
 libide/ctags/ide-ctags-service.h     |    4 +-
 libide/ide-language.c                |   27 ++++
 6 files changed, 328 insertions(+), 1 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index b0e2b8c..f6141b1 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -229,6 +229,8 @@ libide_1_0_la_SOURCES = \
        ctags/ide-ctags-completion-item.h \
        ctags/ide-ctags-completion-provider.c \
        ctags/ide-ctags-completion-provider.h \
+       ctags/ide-ctags-highlighter.c \
+       ctags/ide-ctags-highlighter.h \
        ctags/ide-ctags-index.c \
        ctags/ide-ctags-index.h \
        ctags/ide-ctags-service.c \
diff --git a/libide/ctags/ide-ctags-highlighter.c b/libide/ctags/ide-ctags-highlighter.c
new file mode 100644
index 0000000..c06f920
--- /dev/null
+++ b/libide/ctags/ide-ctags-highlighter.c
@@ -0,0 +1,232 @@
+/* ide-ctags-highlighter.c
+ *
+ * Copyright (C) 2015 Christian Hergert <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-ctags-highlighter.h"
+#include "ide-debug.h"
+
+struct _IdeCtagsHighlighter
+{
+  IdeHighlighter parent_instance;
+  GPtrArray     *indexes;
+};
+
+G_DEFINE_TYPE (IdeCtagsHighlighter, ide_ctags_highlighter, IDE_TYPE_HIGHLIGHTER)
+
+static inline gboolean
+accepts_char (gunichar ch)
+{
+  return (ch == '_' || g_unichar_isalnum (ch));
+}
+
+static gboolean
+select_next_word (GtkTextIter *begin,
+                  GtkTextIter *end)
+{
+  g_assert (begin);
+  g_assert (end);
+
+  *end = *begin;
+
+  while (!accepts_char (gtk_text_iter_get_char (begin)))
+    if (!gtk_text_iter_forward_char (begin))
+      return FALSE;
+
+  *end = *begin;
+
+  while (accepts_char (gtk_text_iter_get_char (end)))
+    if (!gtk_text_iter_forward_char (end))
+      return !gtk_text_iter_equal (begin, end);
+
+  return TRUE;
+}
+
+static const gchar *
+get_tag_from_kind (IdeCtagsIndexEntryKind kind)
+{
+  switch (kind)
+    {
+    case IDE_CTAGS_INDEX_ENTRY_FUNCTION:
+      return IDE_CTAGS_HIGHLIGHTER_FUNCTION_NAME;
+
+    case IDE_CTAGS_INDEX_ENTRY_ENUMERATOR:
+    case IDE_CTAGS_INDEX_ENTRY_ENUMERATION_NAME:
+      return IDE_CTAGS_HIGHLIGHTER_ENUM_NAME;
+
+    case IDE_CTAGS_INDEX_ENTRY_TYPEDEF:
+    case IDE_CTAGS_INDEX_ENTRY_STRUCTURE:
+      return IDE_CTAGS_HIGHLIGHTER_TYPE;
+
+    case IDE_CTAGS_INDEX_ENTRY_ANCHOR:
+    case IDE_CTAGS_INDEX_ENTRY_CLASS_NAME:
+    case IDE_CTAGS_INDEX_ENTRY_DEFINE:
+    case IDE_CTAGS_INDEX_ENTRY_FILE_NAME:
+    case IDE_CTAGS_INDEX_ENTRY_MEMBER:
+    case IDE_CTAGS_INDEX_ENTRY_PROTOTYPE:
+    case IDE_CTAGS_INDEX_ENTRY_UNION:
+    case IDE_CTAGS_INDEX_ENTRY_VARIABLE:
+
+    default:
+      return NULL;
+    }
+}
+
+static const gchar *get_tag (IdeCtagsHighlighter *self,const gchar *word)
+{
+  const IdeCtagsIndexEntry *entries;
+  gsize n_entries;
+  gsize i;
+
+  for (i = 0; i < self->indexes->len; i++)
+    {
+      IdeCtagsIndex *item = g_ptr_array_index (self->indexes, i);
+      entries = ide_ctags_index_lookup_prefix (item, word, &n_entries);
+      if ((entries == NULL) || (n_entries == 0))
+        continue;
+
+      return get_tag_from_kind (entries[0].kind);
+    }
+  return NULL;
+}
+
+static void
+ide_ctags_highlighter_real_update (IdeHighlighter       *highlighter,
+                                   IdeHighlightCallback  callback,
+                                   const GtkTextIter    *range_begin,
+                                   const GtkTextIter    *range_end,
+                                   GtkTextIter          *location)
+{
+  GtkTextBuffer *text_buffer;
+  GtkSourceBuffer *source_buffer;
+  IdeBuffer *buffer;
+  GtkTextIter begin;
+  GtkTextIter end;
+
+  g_assert (IDE_IS_CTAGS_HIGHLIGHTER (highlighter));
+  g_assert (callback != NULL);
+  g_assert (range_begin != NULL);
+  g_assert (range_end != NULL);
+  g_assert (location != NULL);
+
+  if (!(text_buffer = gtk_text_iter_get_buffer (range_begin)) ||
+      !IDE_IS_BUFFER (text_buffer) ||
+      !(source_buffer = GTK_SOURCE_BUFFER (text_buffer)) ||
+      !(buffer = IDE_BUFFER (text_buffer)))
+    return;
+
+  begin = end = *location = *range_begin;
+
+  while (gtk_text_iter_compare (&begin, range_end) < 0)
+    {
+      if (!select_next_word (&begin, &end))
+        goto completed;
+
+      if (gtk_text_iter_compare (&begin, range_end) >= 0)
+        goto completed;
+
+      g_assert (!gtk_text_iter_equal (&begin, &end));
+
+      if (!gtk_source_buffer_iter_has_context_class (source_buffer, &begin, "string") &&
+          !gtk_source_buffer_iter_has_context_class (source_buffer, &begin, "path") &&
+          !gtk_source_buffer_iter_has_context_class (source_buffer, &begin, "comment"))
+        {
+          const gchar *tag;
+          gchar *word;
+
+          word = gtk_text_iter_get_slice (&begin, &end);
+          tag = get_tag (IDE_CTAGS_HIGHLIGHTER (highlighter), word);
+          g_free (word);
+
+          if (tag != NULL)
+            {
+              if (callback (&begin, &end, tag) == IDE_HIGHLIGHT_STOP)
+                {
+                  *location = end;
+                  return;
+                }
+            }
+        }
+
+      begin = end;
+    }
+
+completed:
+  *location = *range_end;
+}
+
+void
+ide_ctags_highlighter_add_index (IdeCtagsHighlighter *self,
+                                 IdeCtagsIndex       *index)
+{
+  GFile *file;
+  gsize i;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_CTAGS_HIGHLIGHTER (self));
+  g_return_if_fail (!index || IDE_IS_CTAGS_INDEX (index));
+  g_return_if_fail (self->indexes != NULL);
+
+  file = ide_ctags_index_get_file (index);
+
+  for (i = 0; i < self->indexes->len; i++)
+    {
+      IdeCtagsIndex *item = g_ptr_array_index (self->indexes, i);
+      GFile *item_file = ide_ctags_index_get_file (item);
+
+      if (g_file_equal (item_file, file))
+        {
+          g_ptr_array_remove_index_fast (self->indexes, i);
+          g_ptr_array_add (self->indexes, g_object_ref (index));
+
+          IDE_EXIT;
+        }
+    }
+
+  g_ptr_array_add (self->indexes, g_object_ref (index));
+
+  IDE_EXIT;
+}
+
+static void
+ide_ctags_highlighter_finalize (GObject *object)
+{
+  IdeCtagsHighlighter *self = (IdeCtagsHighlighter *)object;
+
+  g_clear_pointer (&self->indexes, g_ptr_array_unref);
+
+  G_OBJECT_CLASS (ide_ctags_highlighter_parent_class)->finalize (object);
+}
+
+static void
+ide_ctags_highlighter_class_init (IdeCtagsHighlighterClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeHighlighterClass *highlighter_class = IDE_HIGHLIGHTER_CLASS (klass);
+
+  object_class->finalize = ide_ctags_highlighter_finalize;
+  highlighter_class->update = ide_ctags_highlighter_real_update;
+
+}
+
+static void
+ide_ctags_highlighter_init (IdeCtagsHighlighter *self)
+{
+  self->indexes = g_ptr_array_new_with_free_func (g_object_unref);
+}
diff --git a/libide/ctags/ide-ctags-highlighter.h b/libide/ctags/ide-ctags-highlighter.h
new file mode 100644
index 0000000..f1db144
--- /dev/null
+++ b/libide/ctags/ide-ctags-highlighter.h
@@ -0,0 +1,41 @@
+/* ide-ctags-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_CTAGS_HIGHLIGHTER_H
+#define IDE_CTAGS_HIGHLIGHTER_H
+
+#include "ide-highlighter.h"
+#include "ide-ctags-index.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_CTAGS_HIGHLIGHTER (ide_ctags_highlighter_get_type())
+
+#define IDE_CTAGS_HIGHLIGHTER_TYPE          "c:type"
+#define IDE_CTAGS_HIGHLIGHTER_FUNCTION_NAME "def:function"
+#define IDE_CTAGS_HIGHLIGHTER_ENUM_NAME     "def:constant"
+
+G_DECLARE_FINAL_TYPE (IdeCtagsHighlighter, ide_ctags_highlighter,
+                      IDE, CTAGS_HIGHLIGHTER, IdeHighlighter)
+
+void ide_ctags_highlighter_add_index (IdeCtagsHighlighter *self,
+                                      IdeCtagsIndex       *index);
+
+G_END_DECLS
+
+#endif /* IDE_CTAGS_HIGHLIGHTER_H */
diff --git a/libide/ctags/ide-ctags-service.c b/libide/ctags/ide-ctags-service.c
index a273344..612a57a 100644
--- a/libide/ctags/ide-ctags-service.c
+++ b/libide/ctags/ide-ctags-service.c
@@ -32,12 +32,14 @@
 #include "ide-global.h"
 #include "ide-project.h"
 #include "ide-vcs.h"
+#include "ide-ctags-highlighter.h"
 
 struct _IdeCtagsService
 {
   IdeService                   parent_instance;
 
   GtkSourceCompletionProvider *provider;
+  IdeHighlighter              *highlighter;
   EggTaskCache                *indexes;
   GCancellable                *cancellable;
   IdeCtagsBuilder             *builder;
@@ -124,6 +126,7 @@ ide_ctags_service_tags_loaded_cb (GObject      *object,
 
   g_assert (IDE_IS_CTAGS_INDEX (index));
   ide_ctags_completion_provider_add_index (IDE_CTAGS_COMPLETION_PROVIDER (self->provider), index);
+  ide_ctags_highlighter_add_index (IDE_CTAGS_HIGHLIGHTER (self->highlighter), index);
 
   IDE_EXIT;
 }
@@ -288,6 +291,20 @@ ide_ctags_service_mine (IdeCtagsService *self)
   g_task_run_in_thread (task, ide_ctags_service_miner);
 }
 
+IdeHighlighter *
+ide_ctags_service_get_highlighter (IdeCtagsService *self)
+{
+  g_return_val_if_fail (IDE_IS_CTAGS_SERVICE (self), NULL);
+
+  if (!self->miner_ran)
+    {
+      self->miner_ran = TRUE;
+      ide_ctags_service_mine (self);
+    }
+
+  return self->highlighter;
+}
+
 GtkSourceCompletionProvider *
 ide_ctags_service_get_provider (IdeCtagsService *self)
 {
@@ -365,6 +382,7 @@ ide_ctags_service_finalize (GObject *object)
 
   g_clear_object (&self->indexes);
   g_clear_object (&self->provider);
+  g_clear_object (&self->highlighter);
   g_clear_object (&self->cancellable);
 
   G_OBJECT_CLASS (ide_ctags_service_parent_class)->finalize (object);
@@ -390,6 +408,11 @@ ide_ctags_service_init (IdeCtagsService *self)
   self->provider = g_object_new (IDE_TYPE_CTAGS_COMPLETION_PROVIDER,
                                  NULL);
 
+  self->highlighter = g_object_new (IDE_TYPE_CTAGS_HIGHLIGHTER,
+                                    "context",ide_object_get_context (IDE_OBJECT (self)),
+                                    NULL);
+
+
   self->indexes = egg_task_cache_new ((GHashFunc)g_file_hash,
                                       (GEqualFunc)g_file_equal,
                                       g_object_ref,
diff --git a/libide/ctags/ide-ctags-service.h b/libide/ctags/ide-ctags-service.h
index 3f335c7..e6bfcd0 100644
--- a/libide/ctags/ide-ctags-service.h
+++ b/libide/ctags/ide-ctags-service.h
@@ -22,6 +22,7 @@
 #include <gtksourceview/gtksource.h>
 
 #include "ide-service.h"
+#include "ide-highlighter.h"
 
 G_BEGIN_DECLS
 
@@ -29,7 +30,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCtagsService, ide_ctags_service, IDE, CTAGS_SERVICE, IdeService)
 
-GtkSourceCompletionProvider *ide_ctags_service_get_provider (IdeCtagsService *self);
+GtkSourceCompletionProvider *ide_ctags_service_get_provider    (IdeCtagsService *self);
+IdeHighlighter              *ide_ctags_service_get_highlighter (IdeCtagsService *self);
 
 G_END_DECLS
 
diff --git a/libide/ide-language.c b/libide/ide-language.c
index 56d85c9..d284659 100644
--- a/libide/ide-language.c
+++ b/libide/ide-language.c
@@ -173,6 +173,32 @@ ide_language_real_get_diagnostician (IdeLanguage *self)
   return gDiagnostician;
 }
 
+static IdeHighlighter *
+ide_language_real_get_highlighter (IdeLanguage *self)
+{
+  IdeLanguagePrivate *priv = ide_language_get_instance_private (self);
+
+  g_assert (IDE_IS_LANGUAGE (self));
+
+  if (ide_str_equal0 (priv->id, "c") ||
+      ide_str_equal0 (priv->id, "cpp") ||
+      ide_str_equal0 (priv->id, "chdr") ||
+      ide_str_equal0 (priv->id, "python") ||
+      ide_str_equal0 (priv->id, "js") ||
+      ide_str_equal0 (priv->id, "css") ||
+      ide_str_equal0 (priv->id, "html"))
+    {
+      IdeCtagsService *service;
+      IdeContext *context;
+
+      context = ide_object_get_context (IDE_OBJECT (self));
+      service = ide_context_get_service_typed (context, IDE_TYPE_CTAGS_SERVICE);
+      return ide_ctags_service_get_highlighter (service);
+    }
+
+  return NULL;
+}
+
 /**
  * ide_language_get_highlighter:
  *
@@ -372,6 +398,7 @@ ide_language_class_init (IdeLanguageClass *klass)
 
   klass->get_completion_providers = ide_language_real_get_completion_providers;
   klass->get_diagnostician = ide_language_real_get_diagnostician;
+  klass->get_highlighter = ide_language_real_get_highlighter;
 
   gParamSpecs [PROP_DIAGNOSTICIAN] =
     g_param_spec_object ("diagnostician",


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