[gnome-builder] ctags: delegate building tags to the build system when possible



commit 97468825047020f98f2226f4710421214cf37de9
Author: Christian Hergert <chergert redhat com>
Date:   Mon Oct 12 12:39:31 2015 -0400

    ctags: delegate building tags to the build system when possible
    
    If the build system implements IdeTagsBuilder, we can defer our building
    of tags to that instead of doing it ourself.

 plugins/ctags/ide-ctags-builder.c |   71 +------------------
 plugins/ctags/ide-ctags-builder.h |    3 +-
 plugins/ctags/ide-ctags-index.c   |   32 ++++++++-
 plugins/ctags/ide-ctags-index.h   |    4 +-
 plugins/ctags/ide-ctags-service.c |  140 ++++++++++++++++++++++++++++++++++---
 5 files changed, 169 insertions(+), 81 deletions(-)
---
diff --git a/plugins/ctags/ide-ctags-builder.c b/plugins/ctags/ide-ctags-builder.c
index 291e64a..0935655 100644
--- a/plugins/ctags/ide-ctags-builder.c
+++ b/plugins/ctags/ide-ctags-builder.c
@@ -234,12 +234,12 @@ ide_ctags_builder_build_worker (GTask        *task,
                            g_object_ref (task));
 }
 
-static void
-ide_ctags_builder_do_build (IdeCtagsBuilder *self)
+void
+ide_ctags_builder_rebuild (IdeCtagsBuilder *self)
 {
   g_autoptr(GTask) task = NULL;
 
-  g_assert (IDE_IS_CTAGS_BUILDER (self));
+  g_return_if_fail (IDE_IS_CTAGS_BUILDER (self));
 
   /* Make sure we aren't already in shutdown. */
   if (!ide_object_hold (IDE_OBJECT (self)))
@@ -249,51 +249,6 @@ ide_ctags_builder_do_build (IdeCtagsBuilder *self)
   ide_thread_pool_push_task (IDE_THREAD_POOL_INDEXER, task, ide_ctags_builder_build_worker);
 }
 
-static gboolean
-ide_ctags_builder_build_timeout (gpointer data)
-{
-  IdeCtagsBuilder *self = data;
-
-  g_assert (IDE_IS_CTAGS_BUILDER (self));
-
-  self->build_timeout = 0;
-
-  if (self->is_building == FALSE)
-    {
-      self->is_building = TRUE;
-      ide_ctags_builder_do_build (self);
-    }
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-ide_ctags_builder__buffer_saved_cb (IdeCtagsBuilder  *self,
-                                    IdeBuffer        *buffer,
-                                    IdeBufferManager *buffer_manager)
-{
-  g_assert (IDE_IS_CTAGS_BUILDER (self));
-  g_assert (IDE_IS_BUFFER (buffer));
-  g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
-
-  if (self->build_timeout != 0)
-    {
-      g_source_remove (self->build_timeout);
-      self->build_timeout = 0;
-    }
-
-  /*
-   * TODO: We will need to make ctags code insight check a few keys,
-   *       such as symbol resolving, autocompletion, highlight, etc.
-   */
-  if (!g_settings_get_boolean (self->settings, "ctags-autocompletion"))
-    return;
-
-  self->build_timeout = g_timeout_add_seconds (BUILD_CTAGS_DELAY_SECONDS,
-                                               ide_ctags_builder_build_timeout,
-                                               self);
-}
-
 static void
 ide_ctags_builder__ctags_path_changed (IdeCtagsBuilder *self,
                                        const gchar     *key,
@@ -310,25 +265,6 @@ ide_ctags_builder__ctags_path_changed (IdeCtagsBuilder *self,
 }
 
 static void
-ide_ctags_builder_constructed (GObject *object)
-{
-  IdeCtagsBuilder *self = (IdeCtagsBuilder *)object;
-  IdeBufferManager *buffer_manager;
-  IdeContext *context;
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  buffer_manager = ide_context_get_buffer_manager (context);
-
-  g_signal_connect_object (buffer_manager,
-                           "buffer-saved",
-                           G_CALLBACK (ide_ctags_builder__buffer_saved_cb),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  G_OBJECT_CLASS (ide_ctags_builder_parent_class)->constructed (object);
-}
-
-static void
 ide_ctags_builder_finalize (GObject *object)
 {
   IdeCtagsBuilder *self = (IdeCtagsBuilder *)object;
@@ -351,7 +287,6 @@ ide_ctags_builder_class_init (IdeCtagsBuilderClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  object_class->constructed = ide_ctags_builder_constructed;
   object_class->finalize = ide_ctags_builder_finalize;
 
   gSignals [TAGS_BUILT] =
diff --git a/plugins/ctags/ide-ctags-builder.h b/plugins/ctags/ide-ctags-builder.h
index fe25e2a..c07ba89 100644
--- a/plugins/ctags/ide-ctags-builder.h
+++ b/plugins/ctags/ide-ctags-builder.h
@@ -27,7 +27,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCtagsBuilder, ide_ctags_builder, IDE, CTAGS_BUILDER, IdeObject)
 
-IdeCtagsBuilder *ide_ctags_builder_new (void);
+IdeCtagsBuilder *ide_ctags_builder_new     (void);
+void             ide_ctags_builder_rebuild (IdeCtagsBuilder *self);
 
 G_END_DECLS
 
diff --git a/plugins/ctags/ide-ctags-index.c b/plugins/ctags/ide-ctags-index.c
index f512717..2adfdb6 100644
--- a/plugins/ctags/ide-ctags-index.c
+++ b/plugins/ctags/ide-ctags-index.c
@@ -36,11 +36,14 @@ struct _IdeCtagsIndex
   GBytes    *buffer;
   GFile     *file;
   gchar     *path_root;
+
+  guint64    mtime;
 };
 
 enum {
   PROP_0,
   PROP_FILE,
+  PROP_MTIME,
   PROP_PATH_ROOT,
   LAST_PROP
 };
@@ -311,6 +314,10 @@ ide_ctags_index_get_property (GObject    *object,
       g_value_set_object (value, ide_ctags_index_get_file (self));
       break;
 
+    case PROP_MTIME:
+      g_value_set_uint64 (value, self->mtime);
+      break;
+
     case PROP_PATH_ROOT:
       g_value_set_string (value, ide_ctags_index_get_path_root (self));
       break;
@@ -334,6 +341,10 @@ ide_ctags_index_set_property (GObject      *object,
       ide_ctags_index_set_file (self, g_value_get_object (value));
       break;
 
+    case PROP_MTIME:
+      self->mtime = g_value_get_uint64 (value);
+      break;
+
     case PROP_PATH_ROOT:
       ide_ctags_index_set_path_root (self, g_value_get_string (value));
       break;
@@ -382,6 +393,15 @@ ide_ctags_index_class_init (IdeCtagsIndexClass *klass)
                          G_TYPE_FILE,
                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |G_PARAM_STATIC_STRINGS));
 
+  gParamSpecs [PROP_MTIME] =
+    g_param_spec_uint64 ("mtime",
+                         "Mtime",
+                         "Mtime",
+                         0,
+                         G_MAXUINT64,
+                         0,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gParamSpecs [PROP_PATH_ROOT] =
     g_param_spec_string ("path-root",
                          "Path Root",
@@ -454,7 +474,8 @@ async_initable_iface_init (GAsyncInitableIface *iface)
 
 IdeCtagsIndex *
 ide_ctags_index_new (GFile       *file,
-                     const gchar *path_root)
+                     const gchar *path_root,
+                     guint64      mtime)
 {
   g_autoptr(GFile) parent = NULL;
   g_autofree gchar *real_path_root = NULL;
@@ -470,6 +491,7 @@ ide_ctags_index_new (GFile       *file,
   return g_object_new (IDE_TYPE_CTAGS_INDEX,
                        "file", file,
                        "path-root", path_root,
+                       "mtime", mtime,
                        NULL);
 }
 
@@ -610,3 +632,11 @@ _ide_ctags_index_register_type (GTypeModule *module)
 {
   ide_ctags_index_register_type (module);
 }
+
+guint64
+ide_ctags_index_get_mtime (IdeCtagsIndex *self)
+{
+  g_return_val_if_fail (IDE_IS_CTAGS_INDEX (self), 0);
+
+  return self->mtime;
+}
diff --git a/plugins/ctags/ide-ctags-index.h b/plugins/ctags/ide-ctags-index.h
index ddbcfde..c7848b3 100644
--- a/plugins/ctags/ide-ctags-index.h
+++ b/plugins/ctags/ide-ctags-index.h
@@ -56,7 +56,8 @@ typedef struct
 } IdeCtagsIndexEntry;
 
 IdeCtagsIndex            *ide_ctags_index_new           (GFile                *file,
-                                                         const gchar          *path_root);
+                                                         const gchar          *path_root,
+                                                         guint64               mtime);
 void                      ide_ctags_index_load_async    (IdeCtagsIndex        *self,
                                                          GFile                *file,
                                                          GCancellable         *cancellable,
@@ -76,6 +77,7 @@ const IdeCtagsIndexEntry *ide_ctags_index_lookup        (IdeCtagsIndex        *s
 const IdeCtagsIndexEntry *ide_ctags_index_lookup_prefix (IdeCtagsIndex        *self,
                                                          const gchar          *keyword,
                                                          gsize                *length);
+guint64                   ide_ctags_index_get_mtime     (IdeCtagsIndex        *self);
 
 gint                ide_ctags_index_entry_compare (gconstpointer             a,
                                                    gconstpointer             b);
diff --git a/plugins/ctags/ide-ctags-service.c b/plugins/ctags/ide-ctags-service.c
index bd317c0..0aaa1de 100644
--- a/plugins/ctags/ide-ctags-service.c
+++ b/plugins/ctags/ide-ctags-service.c
@@ -23,28 +23,30 @@
 
 #include "egg-task-cache.h"
 
+#include "ide-buffer-manager.h"
 #include "ide-context.h"
 #include "ide-ctags-builder.h"
 #include "ide-ctags-completion-provider.h"
-#include "ide-ctags-service.h"
+#include "ide-ctags-highlighter.h"
 #include "ide-ctags-index.h"
+#include "ide-ctags-service.h"
 #include "ide-debug.h"
 #include "ide-global.h"
 #include "ide-project.h"
+#include "ide-tags-builder.h"
 #include "ide-vcs.h"
-#include "ide-ctags-highlighter.h"
 
 struct _IdeCtagsService
 {
-  IdeObject                    parent_instance;
+  IdeObject         parent_instance;
 
-  EggTaskCache                *indexes;
-  GCancellable                *cancellable;
-  IdeCtagsBuilder             *builder;
-  GPtrArray                   *highlighters;
-  GPtrArray                   *completions;
+  EggTaskCache     *indexes;
+  GCancellable     *cancellable;
+  IdeCtagsBuilder  *builder;
+  GPtrArray        *highlighters;
+  GPtrArray        *completions;
 
-  guint                        miner_ran : 1;
+  guint             build_tags_timeout;
 };
 
 static void service_iface_init (IdeServiceInterface *iface);
@@ -70,6 +72,18 @@ ide_ctags_service_build_index_init_cb (GObject      *object,
     g_task_return_pointer (task, g_object_ref (index), g_object_unref);
 }
 
+static guint64
+get_file_mtime (GFile *file)
+{
+  g_autoptr(GFileInfo) info = NULL;
+
+  if ((info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                 G_FILE_QUERY_INFO_NONE, NULL, NULL)))
+    return g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+  return 0;
+}
+
 static gchar *
 resolve_path_root (IdeCtagsService *self,
                    GFile           *file)
@@ -128,7 +142,7 @@ ide_ctags_service_build_index_cb (EggTaskCache  *cache,
   g_assert (G_IS_TASK (task));
 
   path_root = resolve_path_root (self, file);
-  index = ide_ctags_index_new (file, path_root);
+  index = ide_ctags_index_new (file, path_root, get_file_mtime (file));
 
   uri = g_file_get_uri (file);
   g_debug ("Building ctags in memory index for %s", uri);
@@ -183,12 +197,29 @@ ide_ctags_service_tags_loaded_cb (GObject      *object,
 }
 
 static gboolean
+file_is_newer (IdeCtagsIndex *index,
+               GFile         *file)
+{
+  g_assert (IDE_IS_CTAGS_INDEX (index));
+  g_assert (G_IS_FILE (file));
+
+  return get_file_mtime (file) > ide_ctags_index_get_mtime (index);
+}
+
+static gboolean
 do_load (gpointer data)
 {
   struct {
     IdeCtagsService *self;
     GFile *file;
   } *pair = data;
+  IdeCtagsIndex *prev;
+
+  if ((prev = egg_task_cache_peek (pair->self->indexes, pair->file)))
+    {
+      if (!file_is_newer (prev, pair->file))
+        goto cleanup;
+    }
 
   egg_task_cache_get_async (pair->self->indexes,
                             pair->file,
@@ -197,6 +228,7 @@ do_load (gpointer data)
                             ide_ctags_service_tags_loaded_cb,
                             g_object_ref (pair->self));
 
+cleanup:
   g_object_unref (pair->self);
   g_object_unref (pair->file);
   g_slice_free1 (sizeof *pair, pair);
@@ -364,13 +396,99 @@ ide_ctags_service_tags_built_cb (IdeCtagsService *self,
 }
 
 static void
+build_system_tags_cb (GObject      *object,
+                      GAsyncResult *result,
+                      gpointer      user_data)
+{
+  IdeTagsBuilder *builder = (IdeTagsBuilder *)object;
+  g_autoptr(IdeCtagsService) self = user_data;
+
+  g_assert (IDE_IS_TAGS_BUILDER (builder));
+
+  ide_ctags_service_mine (self);
+}
+
+static gboolean
+restart_miner (gpointer data)
+{
+  IdeCtagsService *self = data;
+  IdeContext *context;
+
+  g_assert (IDE_IS_CTAGS_SERVICE (self));
+
+  self->build_tags_timeout = 0;
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+
+  if (context != NULL)
+    {
+      IdeBuildSystem *build_system;
+
+      build_system = ide_context_get_build_system (context);
+
+      if (IDE_IS_TAGS_BUILDER (build_system))
+        {
+          IdeVcs *vcs;
+          GFile *workdir;
+
+          vcs = ide_context_get_vcs (context);
+          workdir = ide_vcs_get_working_directory (vcs);
+          ide_tags_builder_build_async (IDE_TAGS_BUILDER (build_system), workdir, TRUE, NULL,
+                                        build_system_tags_cb, g_object_ref (self));;
+          goto finish;
+        }
+    }
+
+  ide_ctags_builder_rebuild (self->builder);
+
+finish:
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+ide_ctags_service_buffer_saved (IdeCtagsService  *self,
+                                IdeBuffer        *buffer,
+                                IdeBufferManager *buffer_manager)
+{
+  g_assert (IDE_IS_CTAGS_SERVICE (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+  g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
+
+  if (self->build_tags_timeout == 0)
+    self->build_tags_timeout = g_timeout_add_seconds (5, restart_miner, self);
+}
+
+static void
 ide_ctags_service_context_loaded (IdeService *service)
 {
   IdeCtagsService *self = (IdeCtagsService *)service;
+  IdeContext *context;
+  IdeBuildSystem *build_system;
+
+  IDE_ENTRY;
 
   g_assert (IDE_IS_CTAGS_SERVICE (self));
 
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_system = ide_context_get_build_system (context);
+
+  if (IDE_IS_TAGS_BUILDER (build_system))
+    {
+      IdeBufferManager *buffer_manager;
+
+      buffer_manager = ide_context_get_buffer_manager (context);
+
+      g_signal_connect_object (buffer_manager,
+                               "buffer-saved",
+                               G_CALLBACK (ide_ctags_service_buffer_saved),
+                               self,
+                               G_CONNECT_SWAPPED);
+    }
+
   ide_ctags_service_mine (self);
+
+  IDE_EXIT;
 }
 
 static void
@@ -402,6 +520,7 @@ ide_ctags_service_stop (IdeService *service)
   if (self->cancellable && !g_cancellable_is_cancelled (self->cancellable))
     g_cancellable_cancel (self->cancellable);
 
+  ide_clear_source (&self->build_tags_timeout);
   g_clear_object (&self->cancellable);
   g_clear_object (&self->builder);
 }
@@ -413,6 +532,7 @@ ide_ctags_service_finalize (GObject *object)
 
   IDE_ENTRY;
 
+  ide_clear_source (&self->build_tags_timeout);
   g_clear_object (&self->indexes);
   g_clear_object (&self->cancellable);
   g_clear_pointer (&self->highlighters, g_ptr_array_unref);


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