[gnome-builder: 66/139] code-index: port to libide-foundry and libide-code



commit 2b3e637ae21bce31b3acbfe1cd15a64fc565cd5b
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 9 17:07:36 2019 -0800

    code-index: port to libide-foundry and libide-code
    
    This ports the code-index plugin to use new components from libide-code
    and libide-foundry.

 src/plugins/code-index/code-index-plugin.c         |  21 +-
 src/plugins/code-index/code-index.gresource.xml    |   2 +-
 src/plugins/code-index/code-index.plugin           |  12 +-
 .../code-index/gbp-code-index-workbench-addin.c    | 759 +++++++++++++++++++++
 .../code-index/gbp-code-index-workbench-addin.h    |  40 ++
 src/plugins/code-index/ide-code-index-builder.c    |  59 +-
 src/plugins/code-index/ide-code-index-builder.h    |   6 +-
 src/plugins/code-index/ide-code-index-index.c      |  38 +-
 src/plugins/code-index/ide-code-index-index.h      |   4 +-
 .../code-index/ide-code-index-search-provider.c    |  22 +-
 .../code-index/ide-code-index-search-provider.h    |   2 +-
 .../code-index/ide-code-index-search-result.c      |  54 +-
 .../code-index/ide-code-index-search-result.h      |  13 +-
 src/plugins/code-index/ide-code-index-service.c    | 703 -------------------
 src/plugins/code-index/ide-code-index-service.h    |  37 -
 .../code-index/ide-code-index-symbol-resolver.c    |  36 +-
 .../code-index/ide-code-index-symbol-resolver.h    |   2 +-
 src/plugins/code-index/meson.build                 |  29 +-
 18 files changed, 948 insertions(+), 891 deletions(-)
---
diff --git a/src/plugins/code-index/code-index-plugin.c b/src/plugins/code-index/code-index-plugin.c
index b324fc392..65029523e 100644
--- a/src/plugins/code-index/code-index-plugin.c
+++ b/src/plugins/code-index/code-index-plugin.c
@@ -1,6 +1,7 @@
 /* code-index-plugin.c
  *
  * Copyright 2017 Anoop Chandu <anoopchandu96 gmail com>
+ * Copyright 2018-2019 Christian Hergert <chergert redhat 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
@@ -18,25 +19,27 @@
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
+#include "config.h"
+
 #include <libpeas/peas.h>
-#include <ide.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+#include <libide-search.h>
 
-#include "ide-code-index-service.h"
 #include "ide-code-index-search-provider.h"
 #include "ide-code-index-symbol-resolver.h"
+#include "gbp-code-index-workbench-addin.h"
 
-void
-ide_code_index_register_types (PeasObjectModule *module)
+_IDE_EXTERN void
+_ide_code_index_register_types (PeasObjectModule *module)
 {
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_SERVICE,
-                                              IDE_TYPE_CODE_INDEX_SERVICE);
-
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_SEARCH_PROVIDER,
                                               IDE_TYPE_CODE_INDEX_SEARCH_PROVIDER);
-
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_SYMBOL_RESOLVER,
                                               IDE_TYPE_CODE_INDEX_SYMBOL_RESOLVER);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKBENCH_ADDIN,
+                                              GBP_TYPE_CODE_INDEX_WORKBENCH_ADDIN);
 }
diff --git a/src/plugins/code-index/code-index.gresource.xml b/src/plugins/code-index/code-index.gresource.xml
index 12fc75e05..bb6304147 100644
--- a/src/plugins/code-index/code-index.gresource.xml
+++ b/src/plugins/code-index/code-index.gresource.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
-  <gresource prefix="/org/gnome/builder/plugins">
+  <gresource prefix="/plugins/code-index">
     <file>code-index.plugin</file>
   </gresource>
 </gresources>
diff --git a/src/plugins/code-index/code-index.plugin b/src/plugins/code-index/code-index.plugin
index 33a7156cc..bffcc36ae 100644
--- a/src/plugins/code-index/code-index.plugin
+++ b/src/plugins/code-index/code-index.plugin
@@ -1,10 +1,10 @@
 [Plugin]
-Module=code-index-plugin
-Name=Code Index
-Description=Manages Code Index and does Global Search and Jump to Definition using Code Index.
 Authors=Anoop Chandu <anoopchandu96 gmail com>
-Copyright=Copyright © 2017 Anoop Chandu
 Builtin=true
-Embedded=ide_code_index_register_types
-X-Symbol-Resolver-Languages=c,chdr,cpp
+Copyright=Copyright © 2017 Anoop Chandu
+Description=Manages Code Index and does Global Search and Jump to Definition using Code Index.
+Embedded=_ide_code_index_register_types
+Module=code-index
+Name=Code Index
 X-Symbol-Resolver-Languages-Priority=200
+X-Symbol-Resolver-Languages=c,chdr,cpp
diff --git a/src/plugins/code-index/gbp-code-index-workbench-addin.c 
b/src/plugins/code-index/gbp-code-index-workbench-addin.c
new file mode 100644
index 000000000..5fdd3f646
--- /dev/null
+++ b/src/plugins/code-index/gbp-code-index-workbench-addin.c
@@ -0,0 +1,759 @@
+/* gbp-code-index-workbench-addin.c
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-code-index-workbench-addin"
+
+#include "config.h"
+
+#include <dazzle.h>
+#include <gtksourceview/gtksource.h>
+#include <libide-foundry.h>
+#include <libide-gui.h>
+#include <libide-plugins.h>
+#include <libide-projects.h>
+#include <libide-vcs.h>
+
+#include "gbp-code-index-workbench-addin.h"
+#include "ide-code-index-builder.h"
+
+#define DEFAULT_INDEX_TIMEOUT_SECS 5
+#define MAX_TRIALS 3
+
+struct _GbpCodeIndexWorkbenchAddin
+{
+  IdeObject               parent_instance;
+
+  IdeWorkbench           *workbench;
+
+  /* The builder to build & update index */
+  IdeCodeIndexBuilder    *builder;
+
+  /* The Index which will store all declarations */
+  IdeCodeIndexIndex      *index;
+
+  /* Queue of directories which needs to be indexed */
+  GQueue                  build_queue;
+  GHashTable             *build_dirs;
+
+  GHashTable             *code_indexers;
+
+  IdeNotification        *notif;
+  GCancellable           *cancellable;
+
+  guint                   paused : 1;
+  guint                   delayed_build_reqeusted : 1;
+};
+
+typedef struct
+{
+  volatile gint               ref_count;
+  GbpCodeIndexWorkbenchAddin *self;
+  GFile                      *directory;
+  guint                       n_trial;
+  guint                       recursive : 1;
+} BuildData;
+
+static void gbp_code_index_workbench_addin_build (GbpCodeIndexWorkbenchAddin *self,
+                                                  GFile                      *directory,
+                                                  gboolean                    recursive,
+                                                  guint                       n_trial);
+
+static void
+remove_source (gpointer source_id)
+{
+  if (source_id != NULL)
+    g_source_remove (GPOINTER_TO_UINT (source_id));
+}
+
+static void
+build_data_unref (BuildData *data)
+{
+  g_assert (data != NULL);
+  g_assert (data->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&data->ref_count))
+    {
+      g_clear_object (&data->self);
+      g_clear_object (&data->directory);
+      g_slice_free (BuildData, data);
+    }
+}
+
+static BuildData *
+build_data_ref (BuildData *data)
+{
+  g_assert (data != NULL);
+  g_assert (data->ref_count > 0);
+  g_atomic_int_inc (&data->ref_count);
+  return data;
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (BuildData, build_data_unref)
+
+static void
+register_notification (GbpCodeIndexWorkbenchAddin *self)
+{
+  g_autoptr(IdeNotification) notif = NULL;
+  g_autoptr(GIcon) icon = NULL;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (self->notif == NULL);
+
+  icon = g_icon_new_for_string ("media-playback-pause-symbolic", NULL);
+
+  notif = ide_notification_new ();
+  ide_notification_set_id (notif, "org.gnome.builder.code-index");
+  ide_notification_set_title (notif, "Indexing Source Code");
+  ide_notification_set_body (notif, "Search, diagnostics, and autocompletion may be limited until 
complete.");
+  ide_notification_set_has_progress (notif, TRUE);
+  ide_notification_set_progress (notif, 0);
+  ide_notification_set_progress_is_imprecise (notif, TRUE);
+  ide_notification_add_button (notif, NULL, icon, "code-index.paused");
+
+  context = ide_workbench_get_context (self->workbench);
+  ide_notification_attach (notif, IDE_OBJECT (context));
+
+  self->notif = g_object_ref (notif);
+}
+
+static void
+unregister_notification (GbpCodeIndexWorkbenchAddin *self)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+
+  if (self->notif != NULL)
+    {
+      ide_notification_withdraw (self->notif);
+      g_clear_object (&self->notif);
+    }
+}
+
+static gboolean
+delay_until_build_completes (GbpCodeIndexWorkbenchAddin *self)
+{
+  IdeBuildPipeline *pipeline;
+  IdeBuildManager *build_manager;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+
+  if (self->delayed_build_reqeusted)
+    return TRUE;
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  g_assert (IDE_IS_CONTEXT (context));
+
+  build_manager = ide_build_manager_from_context (context);
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+
+  if (pipeline == NULL || !ide_build_pipeline_has_configured (pipeline))
+    {
+      self->delayed_build_reqeusted = TRUE;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+gbp_code_index_workbench_addin_build_cb (GObject      *object,
+                                         GAsyncResult *result,
+                                         gpointer      user_data)
+{
+  g_autoptr(GbpCodeIndexWorkbenchAddin) self = user_data;
+  IdeCodeIndexBuilder *builder = (IdeCodeIndexBuilder *)object;
+  g_autoptr(BuildData) bdata = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_CODE_INDEX_BUILDER (builder));
+
+  if (ide_code_index_builder_build_finish (builder, result, &error))
+    g_debug ("Finished building code index");
+  else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+    g_warning ("Failed to build code index: %s", error->message);
+
+  if (ide_object_in_destruction (IDE_OBJECT (self)))
+    return;
+
+  bdata = g_queue_pop_head (&self->build_queue);
+
+  /*
+   * If we're paused, push this item back on the queue to
+   * be processed when we unpause.
+   */
+  if (self->paused)
+    {
+      g_queue_push_head (&self->build_queue, g_steal_pointer (&bdata));
+      return;
+    }
+
+  if (error != NULL &&
+      !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+    {
+      gbp_code_index_workbench_addin_build (self,
+                                            bdata->directory,
+                                            bdata->recursive,
+                                            bdata->n_trial + 1);
+    }
+
+  /* Index next directory */
+  if (!g_queue_is_empty (&self->build_queue))
+    {
+      BuildData *peek = g_queue_peek_head (&self->build_queue);
+
+      g_clear_object (&self->cancellable);
+      self->cancellable = g_cancellable_new ();
+
+      ide_code_index_builder_build_async (builder,
+                                          peek->directory,
+                                          peek->recursive,
+                                          self->cancellable,
+                                          gbp_code_index_workbench_addin_build_cb,
+                                          g_object_ref (self));
+    }
+  else
+    {
+      unregister_notification (self);
+    }
+}
+
+static gboolean
+ide_code_index_serivce_push (BuildData *bdata)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (bdata != NULL);
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (bdata->self));
+  g_assert (G_IS_FILE (bdata->directory));
+
+  if (g_queue_is_empty (&bdata->self->build_queue))
+    {
+      g_queue_push_tail (&bdata->self->build_queue, build_data_ref (bdata));
+
+      g_clear_object (&bdata->self->cancellable);
+      bdata->self->cancellable = g_cancellable_new ();
+
+      register_notification (bdata->self);
+
+      ide_code_index_builder_build_async (bdata->self->builder,
+                                          bdata->directory,
+                                          bdata->recursive,
+                                          bdata->self->cancellable,
+                                          gbp_code_index_workbench_addin_build_cb,
+                                          g_object_ref (bdata->self));
+    }
+  else
+    {
+      g_queue_push_tail (&bdata->self->build_queue, build_data_ref (bdata));
+    }
+
+  if (bdata->self->build_dirs != NULL)
+    g_hash_table_remove (bdata->self->build_dirs, bdata->directory);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+gbp_code_index_workbench_addin_build (GbpCodeIndexWorkbenchAddin *self,
+                                      GFile                      *directory,
+                                      gboolean                    recursive,
+                                      guint                       n_trial)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_FILE (directory));
+
+  if (n_trial > MAX_TRIALS)
+    return;
+
+  /*
+   * If the build system is currently failed, then don't try to
+   * do any indexing now. We'll wait for a successful build that
+   * at least reaches IDE_BUILD_PHASE_CONFIGURE and then trigger
+   * after that.
+   */
+  if (delay_until_build_completes (self))
+    return;
+
+  if (!g_hash_table_lookup (self->build_dirs, directory))
+    {
+      g_autoptr(BuildData) bdata = NULL;
+      guint source_id;
+
+      bdata = g_slice_new0 (BuildData);
+      bdata->ref_count = 1;
+      bdata->self = g_object_ref (self);
+      bdata->directory = g_object_ref (directory);
+      bdata->recursive = recursive;
+      bdata->n_trial = n_trial;
+
+      source_id = g_timeout_add_seconds_full (G_PRIORITY_LOW,
+                                              DEFAULT_INDEX_TIMEOUT_SECS,
+                                              (GSourceFunc) ide_code_index_serivce_push,
+                                              g_steal_pointer (&bdata),
+                                              (GDestroyNotify) build_data_unref);
+
+      g_hash_table_insert (self->build_dirs,
+                           g_object_ref (directory),
+                           GUINT_TO_POINTER (source_id));
+    }
+}
+
+static void
+gbp_code_index_workbench_addin_vcs_changed (GbpCodeIndexWorkbenchAddin *self,
+                                            IdeVcs                     *vcs)
+{
+  GFile *workdir;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_VCS (vcs));
+
+  workdir = ide_vcs_get_workdir (vcs);
+  gbp_code_index_workbench_addin_build (self, workdir, TRUE, 1);
+}
+
+static void
+gbp_code_index_workbench_addin_buffer_saved (GbpCodeIndexWorkbenchAddin *self,
+                                             IdeBuffer                  *buffer,
+                                             IdeBufferManager           *buffer_manager)
+{
+  g_autofree gchar *file_name = NULL;
+  GFile *file;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  file = ide_buffer_get_file (buffer);
+  file_name = g_file_get_uri (file);
+
+  if (!!gbp_code_index_workbench_addin_get_code_indexer (self, file_name))
+    {
+      g_autoptr(GFile) parent = NULL;
+
+      parent = g_file_get_parent (file);
+      gbp_code_index_workbench_addin_build (self, parent, FALSE, 1);
+    }
+}
+
+static void
+gbp_code_index_workbench_addin_file_trashed (GbpCodeIndexWorkbenchAddin *self,
+                                             GFile                      *file,
+                                             IdeProject                 *project)
+{
+  g_autofree gchar *file_name = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_FILE (file));
+
+  file_name = g_file_get_uri (file);
+
+  if (!!gbp_code_index_workbench_addin_get_code_indexer (self, file_name))
+    {
+      g_autoptr(GFile) parent = NULL;
+
+      parent = g_file_get_parent (file);
+      gbp_code_index_workbench_addin_build (self, parent, FALSE, 1);
+    }
+}
+
+static void
+gbp_code_index_workbench_addin_file_renamed (GbpCodeIndexWorkbenchAddin *self,
+                                             GFile                      *src_file,
+                                             GFile                      *dst_file,
+                                             IdeProject                 *project)
+{
+  g_autofree gchar *src_file_name = NULL;
+  g_autofree gchar *dst_file_name = NULL;
+  g_autoptr(GFile) src_parent = NULL;
+  g_autoptr(GFile) dst_parent = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (G_IS_FILE (src_file));
+  g_assert (G_IS_FILE (dst_file));
+
+  src_file_name = g_file_get_uri (src_file);
+  dst_file_name = g_file_get_uri (dst_file);
+
+  src_parent = g_file_get_parent (src_file);
+  dst_parent = g_file_get_parent (dst_file);
+
+  if (g_file_equal (src_parent, dst_parent))
+    {
+      if (NULL != gbp_code_index_workbench_addin_get_code_indexer (self, src_file_name) ||
+          NULL != gbp_code_index_workbench_addin_get_code_indexer (self, dst_file_name))
+        gbp_code_index_workbench_addin_build (self, src_parent, FALSE, 1);
+    }
+  else
+    {
+      if (NULL != gbp_code_index_workbench_addin_get_code_indexer (self, src_file_name))
+        gbp_code_index_workbench_addin_build (self, src_parent, FALSE, 1);
+
+      if (NULL != gbp_code_index_workbench_addin_get_code_indexer (self, dst_file_name))
+        gbp_code_index_workbench_addin_build (self, dst_parent, FALSE, 1);
+    }
+}
+
+static void
+gbp_code_index_workbench_addin_build_finished (GbpCodeIndexWorkbenchAddin *self,
+                                               IdeBuildPipeline           *pipeline,
+                                               IdeBuildManager            *build_manager)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
+
+  if (self->delayed_build_reqeusted &&
+      ide_build_pipeline_has_configured (pipeline))
+    {
+      g_autoptr(GFile) workdir = NULL;
+      IdeContext *context;
+
+      self->delayed_build_reqeusted = FALSE;
+
+      context = ide_object_get_context (IDE_OBJECT (self));
+      workdir = ide_context_ref_workdir (context);
+
+      gbp_code_index_workbench_addin_build (self, workdir, TRUE, 1);
+    }
+}
+
+static void
+gbp_code_index_workbench_addin_load (IdeWorkbenchAddin *addin,
+                                     IdeWorkbench      *workbench)
+{
+  GbpCodeIndexWorkbenchAddin *self = (GbpCodeIndexWorkbenchAddin *)addin;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  self->workbench = workbench;
+
+  context = ide_workbench_get_context (workbench);
+  ide_object_append (IDE_OBJECT (context), IDE_OBJECT (self));
+}
+
+static void
+gbp_code_index_workbench_addin_unload (IdeWorkbenchAddin *addin,
+                                       IdeWorkbench      *workbench)
+{
+  GbpCodeIndexWorkbenchAddin *self = (GbpCodeIndexWorkbenchAddin *)addin;
+  IdeContext *context;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKBENCH (workbench));
+
+  g_clear_pointer (&self->build_dirs, g_hash_table_unref);
+  g_clear_pointer (&self->code_indexers, g_hash_table_unref);
+  ide_clear_and_destroy_object (&self->builder);
+  ide_clear_and_destroy_object (&self->index);
+
+  context = ide_workbench_get_context (workbench);
+  ide_object_remove (IDE_OBJECT (context), IDE_OBJECT (self));
+
+  self->workbench = NULL;
+}
+
+static void
+gbp_code_index_workbench_addin_project_loaded (IdeWorkbenchAddin *addin,
+                                               IdeProjectInfo    *project_info)
+{
+  GbpCodeIndexWorkbenchAddin *self = (GbpCodeIndexWorkbenchAddin *)addin;
+  IdeBufferManager *bufmgr;
+  IdeBuildManager *buildmgr;
+  IdeContext *context;
+  IdeProject *project;
+  IdeVcs *vcs;
+  GFile *workdir;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_PROJECT_INFO (project_info));
+
+  context = ide_workbench_get_context (self->workbench);
+  project = ide_project_from_context (context);
+  bufmgr = ide_buffer_manager_from_context (context);
+  buildmgr = ide_build_manager_from_context (context);
+  vcs = ide_vcs_from_context (context);
+  workdir = ide_vcs_get_workdir (vcs);
+
+  self->code_indexers = g_hash_table_new_full (NULL,
+                                               NULL,
+                                               NULL,
+                                               (GDestroyNotify)ide_object_unref_and_destroy);
+  self->index = ide_code_index_index_new (IDE_OBJECT (self));
+  self->builder = ide_code_index_builder_new (IDE_OBJECT (self), self->index);
+  self->build_dirs = g_hash_table_new_full (g_file_hash,
+                                            (GEqualFunc)g_file_equal,
+                                            g_object_unref,
+                                            remove_source);
+
+  g_signal_connect_object (vcs,
+                           "changed",
+                           G_CALLBACK (gbp_code_index_workbench_addin_vcs_changed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (bufmgr,
+                           "buffer-saved",
+                           G_CALLBACK (gbp_code_index_workbench_addin_buffer_saved),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (buildmgr,
+                           "build-finished",
+                           G_CALLBACK (gbp_code_index_workbench_addin_build_finished),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (project,
+                           "file-trashed",
+                           G_CALLBACK (gbp_code_index_workbench_addin_file_trashed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (project,
+                           "file-renamed",
+                           G_CALLBACK (gbp_code_index_workbench_addin_file_renamed),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  gbp_code_index_workbench_addin_build (self, workdir, TRUE, 1);
+}
+
+static void
+gbp_code_index_workbench_addin_workspace_added (IdeWorkbenchAddin *addin,
+                                                IdeWorkspace      *workspace)
+{
+  GbpCodeIndexWorkbenchAddin *self = (GbpCodeIndexWorkbenchAddin *)addin;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKSPACE (workspace));
+
+  gtk_widget_insert_action_group (GTK_WIDGET (workspace),
+                                  "code-index",
+                                  G_ACTION_GROUP (self));
+}
+
+static void
+gbp_code_index_workbench_addin_workspace_removed (IdeWorkbenchAddin *addin,
+                                                  IdeWorkspace      *workspace)
+{
+  GbpCodeIndexWorkbenchAddin *self = (GbpCodeIndexWorkbenchAddin *)addin;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+  g_assert (IDE_IS_WORKSPACE (workspace));
+
+  gtk_widget_insert_action_group (GTK_WIDGET (workspace), "code-index", NULL);
+}
+
+static void
+workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface)
+{
+  iface->load = gbp_code_index_workbench_addin_load;
+  iface->unload = gbp_code_index_workbench_addin_unload;
+  iface->project_loaded = gbp_code_index_workbench_addin_project_loaded;
+  iface->workspace_added = gbp_code_index_workbench_addin_workspace_added;
+  iface->workspace_removed = gbp_code_index_workbench_addin_workspace_removed;
+}
+
+static void
+gbp_code_index_workbench_addin_paused (GbpCodeIndexWorkbenchAddin *self,
+                                       GVariant                   *state)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+
+  if (state == NULL || !g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
+    return;
+
+  if (g_variant_get_boolean (state))
+    gbp_code_index_workbench_addin_pause (self);
+  else
+    gbp_code_index_workbench_addin_unpause (self);
+}
+
+DZL_DEFINE_ACTION_GROUP (GbpCodeIndexWorkbenchAddin, gbp_code_index_workbench_addin, {
+  { "paused", NULL, NULL, "false", gbp_code_index_workbench_addin_paused },
+})
+
+G_DEFINE_TYPE_WITH_CODE (GbpCodeIndexWorkbenchAddin, gbp_code_index_workbench_addin, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
+                                                gbp_code_index_workbench_addin_init_action_group)
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKBENCH_ADDIN, workbench_addin_iface_init))
+
+static void
+gbp_code_index_workbench_addin_class_init (GbpCodeIndexWorkbenchAddinClass *klass)
+{
+}
+
+static void
+gbp_code_index_workbench_addin_init (GbpCodeIndexWorkbenchAddin *self)
+{
+}
+
+void
+gbp_code_index_workbench_addin_pause (GbpCodeIndexWorkbenchAddin *self)
+{
+  g_return_if_fail (IDE_IS_MAIN_THREAD ());
+  g_return_if_fail (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+
+  if (ide_object_in_destruction (IDE_OBJECT (self)))
+    return;
+
+  if (self->paused)
+    return;
+
+  self->paused = TRUE;
+
+  gbp_code_index_workbench_addin_set_action_state (self,
+                                                   "paused",
+                                                   g_variant_new_boolean (TRUE));
+
+  /*
+   * To pause things, we need to cancel our current task. The completion of the
+   * async task will check for cancelled and leave the build task for another
+   * pass.
+   */
+
+  g_cancellable_cancel (self->cancellable);
+}
+
+void
+gbp_code_index_workbench_addin_unpause (GbpCodeIndexWorkbenchAddin *self)
+{
+  BuildData *peek;
+
+  g_return_if_fail (IDE_IS_MAIN_THREAD ());
+  g_return_if_fail (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self));
+
+  if (ide_object_in_destruction (IDE_OBJECT (self)))
+    return;
+
+  if (!self->paused)
+    return;
+
+  self->paused = FALSE;
+
+  gbp_code_index_workbench_addin_set_action_state (self,
+                                                   "paused",
+                                                   g_variant_new_boolean (FALSE));
+
+  peek = g_queue_peek_head (&self->build_queue);
+
+  if (peek != NULL)
+    {
+      GCancellable *cancellable;
+
+      g_clear_object (&self->cancellable);
+      self->cancellable = cancellable = g_cancellable_new ();
+
+      ide_code_index_builder_build_async (self->builder,
+                                          peek->directory,
+                                          peek->recursive,
+                                          cancellable,
+                                          gbp_code_index_workbench_addin_build_cb,
+                                          g_object_ref (self));
+    }
+}
+
+/**
+ * gbp_code_index_workbench_addin_get_code_indexer:
+ * @self: a #GbpCodeIndexWorkbenchAddin
+ * @file_name: the name of the file to index
+ *
+ * Gets an #IdeCodeIndexer suitable for @file_name.
+ *
+ * Returns: (transfer none) (nullable): an #IdeCodeIndexer or %NULL
+ */
+IdeCodeIndexer *
+gbp_code_index_workbench_addin_get_code_indexer (GbpCodeIndexWorkbenchAddin *self,
+                                                 const gchar                *file_name)
+{
+  GtkSourceLanguageManager *manager;
+  IdeExtensionAdapter *adapter;
+  GtkSourceLanguage *language;
+  const gchar *lang_id;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self), NULL);
+  g_return_val_if_fail (file_name != NULL, NULL);
+
+  if (self->code_indexers == NULL ||
+      !(manager = gtk_source_language_manager_get_default ()) ||
+      !(language = gtk_source_language_manager_guess_language (manager, file_name, NULL)) ||
+      !(lang_id = gtk_source_language_get_id (language)))
+    return NULL;
+
+  lang_id = g_intern_string (lang_id);
+  adapter = g_hash_table_lookup (self->code_indexers, lang_id);
+
+  g_assert (!adapter || IDE_IS_EXTENSION_ADAPTER (adapter));
+
+  if (adapter == NULL)
+    {
+      adapter = ide_extension_adapter_new (IDE_OBJECT (self),
+                                           peas_engine_get_default (),
+                                           IDE_TYPE_CODE_INDEXER,
+                                           "Code-Indexer-Languages",
+                                           lang_id);
+      g_hash_table_insert (self->code_indexers, (gchar *)lang_id, adapter);
+    }
+
+  g_assert (IDE_IS_EXTENSION_ADAPTER (adapter));
+
+  return ide_extension_adapter_get_extension (adapter);
+}
+
+GbpCodeIndexWorkbenchAddin *
+gbp_code_index_workbench_addin_from_context (IdeContext *context)
+{
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  return ide_context_peek_child_typed (context, GBP_TYPE_CODE_INDEX_WORKBENCH_ADDIN);
+}
+
+IdeCodeIndexIndex *
+gbp_code_index_workbench_addin_get_index (GbpCodeIndexWorkbenchAddin *self)
+{
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (self), NULL);
+
+  return self->index;
+}
diff --git a/src/plugins/code-index/gbp-code-index-workbench-addin.h 
b/src/plugins/code-index/gbp-code-index-workbench-addin.h
new file mode 100644
index 000000000..11ec81e3f
--- /dev/null
+++ b/src/plugins/code-index/gbp-code-index-workbench-addin.h
@@ -0,0 +1,40 @@
+/* gbp-code-index-workbench-addin.h
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-code.h>
+
+#include "ide-code-index-index.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CODE_INDEX_WORKBENCH_ADDIN (gbp_code_index_workbench_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCodeIndexWorkbenchAddin, gbp_code_index_workbench_addin, GBP, 
CODE_INDEX_WORKBENCH_ADDIN, IdeObject)
+
+GbpCodeIndexWorkbenchAddin *gbp_code_index_workbench_addin_from_context     (IdeContext                 
*context);
+void                        gbp_code_index_workbench_addin_pause            (GbpCodeIndexWorkbenchAddin 
*self);
+void                        gbp_code_index_workbench_addin_unpause          (GbpCodeIndexWorkbenchAddin 
*self);
+IdeCodeIndexer             *gbp_code_index_workbench_addin_get_code_indexer (GbpCodeIndexWorkbenchAddin 
*self,
+                                                                             const gchar                
*file_name);
+IdeCodeIndexIndex          *gbp_code_index_workbench_addin_get_index        (GbpCodeIndexWorkbenchAddin 
*self);
+
+G_END_DECLS
diff --git a/src/plugins/code-index/ide-code-index-builder.c b/src/plugins/code-index/ide-code-index-builder.c
index 94f7d404d..43ee1b48d 100644
--- a/src/plugins/code-index/ide-code-index-builder.c
+++ b/src/plugins/code-index/ide-code-index-builder.c
@@ -22,14 +22,16 @@
 #define G_LOG_DOMAIN "ide-code-index-builder"
 
 #include <dazzle.h>
+#include <libpeas/peas.h>
+#include <libide-vcs.h>
 #include <string.h>
 
 #include "ide-code-index-builder.h"
+#include "gbp-code-index-workbench-addin.h"
 
 struct _IdeCodeIndexBuilder
 {
   IdeObject            parent;
-  IdeCodeIndexService *service;
   IdeCodeIndexIndex   *index;
 };
 
@@ -103,7 +105,6 @@ typedef struct
 enum {
   PROP_0,
   PROP_INDEX,
-  PROP_SERVICE,
   N_PROPS
 };
 
@@ -301,7 +302,6 @@ ide_code_index_builder_dispose (GObject *object)
   IdeCodeIndexBuilder *self = (IdeCodeIndexBuilder *)object;
 
   g_clear_object (&self->index);
-  g_clear_object (&self->service);
 
   G_OBJECT_CLASS (ide_code_index_builder_parent_class)->dispose (object);
 }
@@ -320,10 +320,6 @@ ide_code_index_builder_get_property (GObject    *object,
       g_value_set_object (value, self->index);
       break;
 
-    case PROP_SERVICE:
-      g_value_set_object (value, self->service);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -343,10 +339,6 @@ ide_code_index_builder_set_property (GObject      *object,
       self->index = g_value_dup_object (value);
       break;
 
-    case PROP_SERVICE:
-      self->service = g_value_dup_object (value);
-      break;
-
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -368,13 +360,6 @@ ide_code_index_builder_class_init (IdeCodeIndexBuilderClass *klass)
                          IDE_TYPE_CODE_INDEX_INDEX,
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
-  properties [PROP_SERVICE] =
-    g_param_spec_object ("service",
-                         "Service",
-                         "The service to query for various build information",
-                         IDE_TYPE_CODE_INDEX_SERVICE,
-                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
@@ -384,18 +369,15 @@ ide_code_index_builder_init (IdeCodeIndexBuilder *self)
 }
 
 IdeCodeIndexBuilder *
-ide_code_index_builder_new (IdeContext          *context,
-                            IdeCodeIndexService *service,
-                            IdeCodeIndexIndex   *index)
+ide_code_index_builder_new (IdeObject         *parent,
+                            IdeCodeIndexIndex *index)
 {
-  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
-  g_return_val_if_fail (IDE_IS_CODE_INDEX_SERVICE (service), NULL);
+  g_return_val_if_fail (IDE_IS_OBJECT (parent), NULL);
   g_return_val_if_fail (IDE_IS_CODE_INDEX_INDEX (index), NULL);
 
   return g_object_new (IDE_TYPE_CODE_INDEX_BUILDER,
-                       "context", context,
-                       "service", service,
                        "index", index,
+                       "parent", parent,
                        NULL);
 }
 
@@ -780,7 +762,7 @@ get_changes_async (IdeCodeIndexBuilder *self,
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  vcs = ide_context_get_vcs (context);
+  vcs = ide_vcs_from_context (context);
 
   task = ide_task_new (self, cancellable, callback, user_data);
   ide_task_set_source_tag (task, get_changes_async);
@@ -821,8 +803,6 @@ get_changes_finish (IdeCodeIndexBuilder  *self,
  * @fuzzy_builder: the fuzzy index builder to append
  *
  * This will incrementally add entries to the builder.
- *
- * Since: 3.32
  */
 static void
 add_entries_to_index (GPtrArray               *entries,
@@ -1155,6 +1135,7 @@ index_directory_async (IdeCodeIndexBuilder *self,
                        GAsyncReadyCallback  callback,
                        gpointer             user_data)
 {
+  g_autoptr(GbpCodeIndexWorkbenchAddin) addin = NULL;
   g_autoptr(IdeTask) task = NULL;
   IndexDirectoryData *idd;
   GHashTableIter iter;
@@ -1186,24 +1167,24 @@ index_directory_async (IdeCodeIndexBuilder *self,
 
   idd->n_active++;
 
+  addin = GBP_CODE_INDEX_WORKBENCH_ADDIN (ide_object_ref_parent (IDE_OBJECT (self)));
+
   while (g_hash_table_iter_next (&iter, &k, &v))
     {
-      IdeFile *file = k;
+      GFile *file = k;
       const gchar * const *file_flags = v;
-      const gchar *path = ide_file_get_path (file);
-      GFile *gfile = ide_file_get_file (file);
+      const gchar *path = g_file_peek_path (file);
       IdeCodeIndexer *indexer;
 
-      g_assert (IDE_IS_FILE (file));
-      g_assert (G_IS_FILE (gfile));
+      g_assert (G_IS_FILE (file));
       g_assert (path != NULL);
-      g_assert (IDE_IS_CODE_INDEX_SERVICE (self->service));
+      g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (addin));
 
-      if ((indexer = ide_code_index_service_get_code_indexer (self->service, path)))
+      if ((indexer = gbp_code_index_workbench_addin_get_code_indexer (addin, path)))
         {
           idd->n_active++;
           ide_code_indexer_index_file_async (indexer,
-                                             gfile,
+                                             file,
                                              file_flags,
                                              cancellable,
                                              index_directory_index_file_cb,
@@ -1427,9 +1408,9 @@ ide_code_index_builder_build_async (IdeCodeIndexBuilder *self,
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  build_system = ide_context_get_build_system (context);
-  vcs = ide_context_get_vcs (context);
-  workdir = ide_vcs_get_working_directory (vcs);
+  build_system = ide_build_system_from_context (context);
+  vcs = ide_vcs_from_context (context);
+  workdir = ide_vcs_get_workdir (vcs);
   relative = g_file_get_relative_path (workdir, directory);
   index_dir = ide_context_cache_file (context, "code-index", relative, NULL);
 
diff --git a/src/plugins/code-index/ide-code-index-builder.h b/src/plugins/code-index/ide-code-index-builder.h
index 58405b0f0..ff54714a5 100644
--- a/src/plugins/code-index/ide-code-index-builder.h
+++ b/src/plugins/code-index/ide-code-index-builder.h
@@ -21,10 +21,9 @@
 
 #pragma once
 
-#include <ide.h>
+#include <libide-foundry.h>
 
 #include "ide-code-index-index.h"
-#include "ide-code-index-service.h"
 
 G_BEGIN_DECLS
 
@@ -32,8 +31,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCodeIndexBuilder, ide_code_index_builder, IDE, CODE_INDEX_BUILDER, IdeObject)
 
-IdeCodeIndexBuilder *ide_code_index_builder_new          (IdeContext           *context,
-                                                          IdeCodeIndexService  *service,
+IdeCodeIndexBuilder *ide_code_index_builder_new          (IdeObject            *parent,
                                                           IdeCodeIndexIndex    *index);
 void                 ide_code_index_builder_drop_caches  (IdeCodeIndexBuilder  *self);
 void                 ide_code_index_builder_build_async  (IdeCodeIndexBuilder  *self,
diff --git a/src/plugins/code-index/ide-code-index-index.c b/src/plugins/code-index/ide-code-index-index.c
index bbcf07518..d9a449747 100644
--- a/src/plugins/code-index/ide-code-index-index.c
+++ b/src/plugins/code-index/ide-code-index-index.c
@@ -174,8 +174,6 @@ directory_index_new (GFile         *directory,
  *
  * Thread safety: you may call this function from a thread so long as the
  *   thread has a reference to @self.
- *
- * Since: 3.32
  */
 gboolean
 ide_code_index_index_load (IdeCodeIndexIndex   *self,
@@ -229,8 +227,8 @@ static IdeCodeIndexSearchResult *
 ide_code_index_index_create_search_result (IdeContext       *context,
                                            const FuzzyMatch *fuzzy_match)
 {
-  g_autoptr(IdeFile) file = NULL;
-  g_autoptr(IdeSourceLocation) location = NULL;
+  g_autoptr(GFile) file = NULL;
+  g_autoptr(IdeLocation) location = NULL;
   g_autoptr(GString) subtitle = NULL;
   const gchar *key;
   const gchar *icon_name;
@@ -253,7 +251,7 @@ ide_code_index_index_create_search_result (IdeContext       *context,
   g_variant_get (value, "(uuuuu)", &file_id, &line, &line_offset, &flags, &kind);
 
   /* Ignore variables in global search */
-  if (kind == IDE_SYMBOL_VARIABLE)
+  if (kind == IDE_SYMBOL_KIND_VARIABLE)
     return NULL;
 
   key = dzl_fuzzy_index_match_get_key (fuzzy_match->match);
@@ -262,8 +260,8 @@ ide_code_index_index_create_search_result (IdeContext       *context,
 
   path = dzl_fuzzy_index_get_metadata_string (fuzzy_match->index, num);
 
-  file = ide_file_new_for_path (context, path);
-  location = ide_source_location_new (file, line - 1, line_offset - 1, 0);
+  file = g_file_new_for_path (path);
+  location = ide_location_new (file, line - 1, line_offset - 1);
 
   icon_name = ide_symbol_kind_get_icon_name (kind);
   score = dzl_fuzzy_index_match_get_score (fuzzy_match->match);
@@ -273,7 +271,7 @@ ide_code_index_index_create_search_result (IdeContext       *context,
   if (NULL != (shortname = strrchr (path, G_DIR_SEPARATOR)))
     g_string_append (subtitle, shortname + 1);
 
-  if ((kind == IDE_SYMBOL_FUNCTION) && !(flags & IDE_SYMBOL_FLAGS_IS_DEFINITION))
+  if ((kind == IDE_SYMBOL_KIND_FUNCTION) && !(flags & IDE_SYMBOL_FLAGS_IS_DEFINITION))
     {
       /* translators: "Declaration" is describing a function that is defined in a header
        *              file (.h) rather than a source file (.c).
@@ -491,16 +489,15 @@ IdeSymbol *
 ide_code_index_index_lookup_symbol (IdeCodeIndexIndex *self,
                                     const gchar       *key)
 {
-  g_autoptr(IdeSourceLocation) declaration = NULL;
-  g_autoptr(IdeSourceLocation) definition = NULL;
-  g_autoptr(IdeFile) file = NULL;
+  g_autoptr(IdeLocation) declaration = NULL;
+  g_autoptr(IdeLocation) definition = NULL;
+  g_autoptr(GFile) file = NULL;
   g_autoptr(GMutexLocker) locker = NULL;
   g_autofree gchar *name = NULL;
-  IdeSymbolKind kind = IDE_SYMBOL_NONE;
+  IdeSymbolKind kind = IDE_SYMBOL_KIND_NONE;
   IdeSymbolFlags flags = IDE_SYMBOL_FLAGS_NONE;
   DzlFuzzyIndex *symbol_names = NULL;
   const DirectoryIndex *dir_index = NULL;
-  IdeContext *context;
   const gchar *filename;
   guint32 file_id = 0;
   guint32 line = 0;
@@ -541,15 +538,14 @@ ide_code_index_index_lookup_symbol (IdeCodeIndexIndex *self,
   g_snprintf (num, sizeof(num), "%u", file_id);
 
   filename = dzl_fuzzy_index_get_metadata_string (symbol_names, num);
-  context = ide_object_get_context (IDE_OBJECT (self));
-  file = ide_file_new_for_path (context, filename);
+  file = g_file_new_for_path (filename);
 
   if (flags & IDE_SYMBOL_FLAGS_IS_DEFINITION)
-    definition = ide_source_location_new (file, line - 1, line_offset - 1, 0);
+    definition = ide_location_new (file, line - 1, line_offset - 1);
   else
-    declaration = ide_source_location_new (file, line - 1, line_offset - 1, 0);
+    declaration = ide_location_new (file, line - 1, line_offset - 1);
 
-  return ide_symbol_new (name, kind, flags, declaration, definition, NULL);
+  return ide_symbol_new (name, kind, flags, definition, declaration);
 }
 
 static void
@@ -583,9 +579,11 @@ ide_code_index_index_class_init (IdeCodeIndexIndexClass *klass)
 }
 
 IdeCodeIndexIndex *
-ide_code_index_index_new (IdeContext *context)
+ide_code_index_index_new (IdeObject *parent)
 {
+  g_return_val_if_fail (IDE_IS_OBJECT (parent), NULL);
+
   return g_object_new (IDE_TYPE_CODE_INDEX_INDEX,
-                       "context", context,
+                       "parent", parent,
                        NULL);
 }
diff --git a/src/plugins/code-index/ide-code-index-index.h b/src/plugins/code-index/ide-code-index-index.h
index 9bc64dd97..27681a3df 100644
--- a/src/plugins/code-index/ide-code-index-index.h
+++ b/src/plugins/code-index/ide-code-index-index.h
@@ -20,7 +20,7 @@
 
 #pragma once
 
-#include <ide.h>
+#include <libide-foundry.h>
 
 G_BEGIN_DECLS
 
@@ -28,7 +28,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCodeIndexIndex, ide_code_index_index, IDE, CODE_INDEX_INDEX, IdeObject)
 
-IdeCodeIndexIndex *ide_code_index_index_new             (IdeContext           *context);
+IdeCodeIndexIndex *ide_code_index_index_new             (IdeObject            *parent);
 gboolean           ide_code_index_index_load            (IdeCodeIndexIndex    *self,
                                                          GFile                *directory,
                                                          GFile                *source_directory,
diff --git a/src/plugins/code-index/ide-code-index-search-provider.c 
b/src/plugins/code-index/ide-code-index-search-provider.c
index 4a0e6986e..2efc86e3e 100644
--- a/src/plugins/code-index/ide-code-index-search-provider.c
+++ b/src/plugins/code-index/ide-code-index-search-provider.c
@@ -20,9 +20,12 @@
 
 #define G_LOG_DOMAIN "ide-code-index-search-provider"
 
+#include <libide-code.h>
+#include <libide-foundry.h>
+
 #include "ide-code-index-search-provider.h"
-#include "ide-code-index-service.h"
 #include "ide-code-index-index.h"
+#include "gbp-code-index-workbench-addin.h"
 
 static void
 populate_cb (GObject      *object,
@@ -57,8 +60,8 @@ ide_code_index_search_provider_search_async (IdeSearchProvider   *provider,
                                              gpointer             user_data)
 {
   IdeCodeIndexSearchProvider *self = (IdeCodeIndexSearchProvider *)provider;
+  GbpCodeIndexWorkbenchAddin *addin = NULL;
   g_autoptr(IdeTask) task = NULL;
-  IdeCodeIndexService *service;
   IdeCodeIndexIndex *index;
   IdeContext *context;
 
@@ -72,10 +75,17 @@ ide_code_index_search_provider_search_async (IdeSearchProvider   *provider,
   context = ide_object_get_context (IDE_OBJECT (self));
   g_assert (IDE_IS_CONTEXT (context));
 
-  service = ide_context_get_service_typed (context, IDE_TYPE_CODE_INDEX_SERVICE);
-  g_assert (IDE_IS_CODE_INDEX_SERVICE (service));
-
-  index = ide_code_index_service_get_index (service);
+  if (!ide_context_has_project (context) ||
+      !(addin = gbp_code_index_workbench_addin_from_context (context)))
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_SUPPORTED,
+                                 "Code index requires a project");
+      IDE_EXIT;
+    }
+
+  index = gbp_code_index_workbench_addin_get_index (addin);
 
   task = ide_task_new (self, cancellable, callback, user_data);
   ide_task_set_source_tag (task, ide_code_index_search_provider_search_async);
diff --git a/src/plugins/code-index/ide-code-index-search-provider.h 
b/src/plugins/code-index/ide-code-index-search-provider.h
index e1edce804..b0b70d06a 100644
--- a/src/plugins/code-index/ide-code-index-search-provider.h
+++ b/src/plugins/code-index/ide-code-index-search-provider.h
@@ -20,7 +20,7 @@
 
 #pragma once
 
-#include <ide.h>
+#include <libide-search.h>
 
 G_BEGIN_DECLS
 
diff --git a/src/plugins/code-index/ide-code-index-search-result.c 
b/src/plugins/code-index/ide-code-index-search-result.c
index 1104fda5d..8425fd09a 100644
--- a/src/plugins/code-index/ide-code-index-search-result.c
+++ b/src/plugins/code-index/ide-code-index-search-result.c
@@ -20,12 +20,17 @@
 
 #define G_LOG_DOMAIN "ide-code-index-search-result"
 
+#include "config.h"
+
+#include <libide-code.h>
+#include <libide-editor.h>
+
 #include "ide-code-index-search-result.h"
 
 struct _IdeCodeIndexSearchResult
 {
-  IdeSearchResult    parent;
-  IdeSourceLocation *location;
+  IdeSearchResult  parent;
+  IdeLocation     *location;
 };
 
 G_DEFINE_TYPE (IdeCodeIndexSearchResult, ide_code_index_search_result, IDE_TYPE_SEARCH_RESULT)
@@ -38,14 +43,23 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
-static IdeSourceLocation *
-ide_code_index_search_result_get_source_location (IdeSearchResult *result)
+static void
+ide_code_index_search_result_activate (IdeSearchResult *result,
+                                       GtkWidget       *last_focus)
 {
   IdeCodeIndexSearchResult *self = (IdeCodeIndexSearchResult *)result;
+  IdeWorkspace *workspace;
+  IdeSurface *editor;
+
+  g_assert (IDE_IS_CODE_INDEX_SEARCH_RESULT (self));
+  g_assert (GTK_IS_WIDGET (last_focus));
 
-  g_return_val_if_fail (IDE_IS_CODE_INDEX_SEARCH_RESULT (self), NULL);
+  if (!last_focus)
+    return;
 
-  return ide_source_location_ref (self->location);
+  if ((workspace = ide_widget_get_workspace (last_focus)) &&
+      (editor = ide_workspace_get_surface_by_name (workspace, "editor")))
+    ide_editor_surface_focus_location (IDE_EDITOR_SURFACE (editor), self->location);
 }
 
 static void
@@ -59,7 +73,7 @@ ide_code_index_search_result_get_property (GObject    *object,
   switch (prop_id)
     {
     case PROP_LOCATION:
-      g_value_set_boxed (value, self->location);
+      g_value_set_object (value, self->location);
       break;
 
     default:
@@ -78,7 +92,7 @@ ide_code_index_search_result_set_property (GObject      *object,
   switch (prop_id)
     {
     case PROP_LOCATION:
-      self->location = g_value_dup_boxed (value);
+      self->location = g_value_dup_object (value);
       break;
 
     default:
@@ -91,7 +105,7 @@ ide_code_index_search_result_finalize (GObject *object)
 {
   IdeCodeIndexSearchResult *self = (IdeCodeIndexSearchResult *)object;
 
-  g_clear_pointer (&self->location, ide_source_location_unref);
+  g_clear_object (&self->location);
 
   G_OBJECT_CLASS (ide_code_index_search_result_parent_class)->finalize (object);
 }
@@ -106,14 +120,14 @@ ide_code_index_search_result_class_init (IdeCodeIndexSearchResultClass *klass)
   object_class->set_property = ide_code_index_search_result_set_property;
   object_class->finalize = ide_code_index_search_result_finalize;
 
-  result_class->get_source_location = ide_code_index_search_result_get_source_location;
+  result_class->activate = ide_code_index_search_result_activate;
 
   properties [PROP_LOCATION] =
-    g_param_spec_boxed ("location",
-                        "location",
-                        "Location of symbol.",
-                        IDE_TYPE_SOURCE_LOCATION,
-                        (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+    g_param_spec_object ("location",
+                         "location",
+                         "Location of symbol.",
+                         IDE_TYPE_LOCATION,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
@@ -124,11 +138,11 @@ ide_code_index_search_result_init (IdeCodeIndexSearchResult *self)
 }
 
 IdeCodeIndexSearchResult *
-ide_code_index_search_result_new (const gchar       *title,
-                                  const gchar       *subtitle,
-                                  const gchar       *icon_name,
-                                  IdeSourceLocation *location,
-                                  gfloat             score)
+ide_code_index_search_result_new (const gchar *title,
+                                  const gchar *subtitle,
+                                  const gchar *icon_name,
+                                  IdeLocation *location,
+                                  gfloat       score)
 {
   return g_object_new (IDE_TYPE_CODE_INDEX_SEARCH_RESULT,
                        "title", title,
diff --git a/src/plugins/code-index/ide-code-index-search-result.h 
b/src/plugins/code-index/ide-code-index-search-result.h
index c927987ab..519221dc9 100644
--- a/src/plugins/code-index/ide-code-index-search-result.h
+++ b/src/plugins/code-index/ide-code-index-search-result.h
@@ -20,7 +20,8 @@
 
 #pragma once
 
-#include <ide.h>
+#include <libide-code.h>
+#include <libide-search.h>
 
 G_BEGIN_DECLS
 
@@ -28,10 +29,10 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeCodeIndexSearchResult, ide_code_index_search_result, IDE, CODE_INDEX_SEARCH_RESULT, 
IdeSearchResult)
 
-IdeCodeIndexSearchResult *ide_code_index_search_result_new (const gchar       *title,
-                                                            const gchar       *subtitle,
-                                                            const gchar       *icon_name,
-                                                            IdeSourceLocation *location,
-                                                            gfloat             score);
+IdeCodeIndexSearchResult *ide_code_index_search_result_new (const gchar *title,
+                                                            const gchar *subtitle,
+                                                            const gchar *icon_name,
+                                                            IdeLocation *location,
+                                                            gfloat       score);
 
 G_END_DECLS
diff --git a/src/plugins/code-index/ide-code-index-symbol-resolver.c 
b/src/plugins/code-index/ide-code-index-symbol-resolver.c
index f5830296f..ee877ab39 100644
--- a/src/plugins/code-index/ide-code-index-symbol-resolver.c
+++ b/src/plugins/code-index/ide-code-index-symbol-resolver.c
@@ -20,7 +20,7 @@
 
 #define G_LOG_DOMAIN "code-index-symbol-resolver"
 
-#include "ide-code-index-service.h"
+#include "gbp-code-index-workbench-addin.h"
 #include "ide-code-index-symbol-resolver.h"
 
 static void
@@ -29,12 +29,12 @@ ide_code_index_symbol_resolver_lookup_cb (GObject      *object,
                                           gpointer      user_data)
 {
   IdeCodeIndexer *code_indexer = (IdeCodeIndexer *)object;
+  GbpCodeIndexWorkbenchAddin *addin = NULL;
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(IdeSymbol) symbol = NULL;
   g_autoptr(GError) error = NULL;
   g_autofree gchar *key = NULL;
   IdeCodeIndexSymbolResolver *self;
-  IdeCodeIndexService *service;
   IdeCodeIndexIndex *index;
   IdeContext *context;
 
@@ -55,10 +55,10 @@ ide_code_index_symbol_resolver_lookup_cb (GObject      *object,
   context = ide_object_get_context (IDE_OBJECT (self));
   g_assert (IDE_IS_CONTEXT (context));
 
-  service = ide_context_get_service_typed (context, IDE_TYPE_CODE_INDEX_SERVICE);
-  g_assert (IDE_IS_CODE_INDEX_SERVICE (service));
+  addin = gbp_code_index_workbench_addin_from_context (context);
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (addin));
 
-  index = ide_code_index_service_get_index (service);
+  index = gbp_code_index_workbench_addin_get_index (addin);
   g_assert (IDE_IS_CODE_INDEX_INDEX (index));
 
   symbol = ide_code_index_index_lookup_symbol (index, key);
@@ -66,7 +66,7 @@ ide_code_index_symbol_resolver_lookup_cb (GObject      *object,
   if (symbol != NULL)
     ide_task_return_pointer (task,
                              g_steal_pointer (&symbol),
-                             (GDestroyNotify)ide_symbol_unref);
+                             g_object_unref);
   else
     ide_task_return_new_error (task,
                                G_IO_ERROR,
@@ -77,7 +77,7 @@ ide_code_index_symbol_resolver_lookup_cb (GObject      *object,
 typedef struct
 {
   IdeCodeIndexer    *code_indexer;
-  IdeSourceLocation *location;
+  IdeLocation *location;
 } LookupSymbol;
 
 static void
@@ -86,7 +86,7 @@ lookup_symbol_free (gpointer data)
   LookupSymbol *state = data;
 
   g_clear_object (&state->code_indexer);
-  g_clear_pointer (&state->location, ide_source_location_unref);
+  g_clear_object (&state->location);
   g_slice_free (LookupSymbol, state);
 }
 
@@ -132,20 +132,20 @@ ide_code_index_symbol_resolver_lookup_flags_cb (GObject      *object,
 
 static void
 ide_code_index_symbol_resolver_lookup_symbol_async (IdeSymbolResolver   *resolver,
-                                                    IdeSourceLocation   *location,
+                                                    IdeLocation   *location,
                                                     GCancellable        *cancellable,
                                                     GAsyncReadyCallback  callback,
                                                     gpointer             user_data)
 {
   IdeCodeIndexSymbolResolver *self = (IdeCodeIndexSymbolResolver *)resolver;
+  GbpCodeIndexWorkbenchAddin *addin;
   g_autoptr(IdeTask) task = NULL;
-  IdeCodeIndexService *service;
   IdeCodeIndexer *code_indexer;
   IdeBuildSystem *build_system;
   const gchar *path;
   IdeContext *context;
-  IdeFile *file;
   LookupSymbol *lookup;
+  GFile *file;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_CODE_INDEX_SYMBOL_RESOLVER (self));
@@ -159,14 +159,14 @@ ide_code_index_symbol_resolver_lookup_symbol_async (IdeSymbolResolver   *resolve
   context = ide_object_get_context (IDE_OBJECT (self));
   g_assert (IDE_IS_CONTEXT (context));
 
-  service = ide_context_get_service_typed (context, IDE_TYPE_CODE_INDEX_SERVICE);
-  g_assert (IDE_IS_CODE_INDEX_SERVICE (service));
+  addin = gbp_code_index_workbench_addin_from_context (context);
+  g_assert (GBP_IS_CODE_INDEX_WORKBENCH_ADDIN (addin));
 
-  file = ide_source_location_get_file (location);
-  path = ide_file_get_path (file);
+  file = ide_location_get_file (location);
+  path = g_file_peek_path (file);
   g_assert (path != NULL);
 
-  code_indexer = ide_code_index_service_get_code_indexer (service, path);
+  code_indexer = gbp_code_index_workbench_addin_get_code_indexer (addin, path);
   g_assert (!code_indexer || IDE_IS_CODE_INDEXER (code_indexer));
 
   if (code_indexer == NULL)
@@ -178,12 +178,12 @@ ide_code_index_symbol_resolver_lookup_symbol_async (IdeSymbolResolver   *resolve
       return;
     }
 
-  build_system = ide_context_get_build_system (context);
+  build_system = ide_build_system_from_context (context);
   g_assert (IDE_IS_BUILD_SYSTEM (build_system));
 
   lookup = g_slice_new0 (LookupSymbol);
   lookup->code_indexer = g_object_ref (code_indexer);
-  lookup->location = ide_source_location_ref (location);
+  lookup->location = g_object_ref (location);
 
   ide_task_set_task_data (task, lookup, lookup_symbol_free);
 
diff --git a/src/plugins/code-index/ide-code-index-symbol-resolver.h 
b/src/plugins/code-index/ide-code-index-symbol-resolver.h
index 3f17a8c73..a4cd69bd1 100644
--- a/src/plugins/code-index/ide-code-index-symbol-resolver.h
+++ b/src/plugins/code-index/ide-code-index-symbol-resolver.h
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include <ide.h>
+#include <libide-foundry.h>
 
 G_BEGIN_DECLS
 
diff --git a/src/plugins/code-index/meson.build b/src/plugins/code-index/meson.build
index 290d8cf77..e1faf9015 100644
--- a/src/plugins/code-index/meson.build
+++ b/src/plugins/code-index/meson.build
@@ -1,28 +1,21 @@
-if get_option('with_code_index')
+if get_option('plugin_code_index')
 
-code_index_resources = gnome.compile_resources(    
-  'ide-code-index-resources',                      
-  'code-index.gresource.xml',                      
-  c_name: 'ide_code_index',                        
-)                                           
-
-code_index_sources = [
+plugins_sources += files([
   'code-index-plugin.c',
   'ide-code-index-builder.c',
-  'ide-code-index-builder.h',
   'ide-code-index-index.c',
-  'ide-code-index-index.h',
   'ide-code-index-search-provider.c',
-  'ide-code-index-search-provider.h',
   'ide-code-index-search-result.c',
-  'ide-code-index-search-result.h',
-  'ide-code-index-service.c',
-  'ide-code-index-service.h',
+  'gbp-code-index-workbench-addin.c',
   'ide-code-index-symbol-resolver.c',
-  'ide-code-index-symbol-resolver.h',
-]
+])
+
+plugin_code_index_resources = gnome.compile_resources(
+  'code-index-resources',
+  'code-index.gresource.xml',
+  c_name: 'gbp_code_index',
+)
 
-gnome_builder_plugins_sources += files(code_index_sources)
-gnome_builder_plugins_sources += code_index_resources[0]
+plugins_sources += plugin_code_index_resources[0]
 
 endif


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