[gnome-builder] libide: add search provider for git filenames



commit dc6e0cedcbb1541b73365278fe65939301f272fe
Author: Christian Hergert <christian hergert me>
Date:   Mon Feb 16 21:24:53 2015 -0800

    libide: add search provider for git filenames

 libide/Makefile.am                   |    4 +
 libide/git/ide-git-search-index.c    |  469 ++++++++++++++++++++++++++++++++++
 libide/git/ide-git-search-index.h    |   39 +++
 libide/git/ide-git-search-provider.c |  215 ++++++++++++++++
 libide/git/ide-git-search-provider.h |   35 +++
 libide/ide.c                         |    6 +
 6 files changed, 768 insertions(+), 0 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index d89293e..ad64a95 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -30,6 +30,8 @@ libide_1_0_la_public_sources = \
        libide/directory/ide-directory-vcs.h \
        libide/editorconfig/ide-editorconfig-file-settings.c \
        libide/editorconfig/ide-editorconfig-file-settings.h \
+       libide/git/ide-git-search-provider.c \
+       libide/git/ide-git-search-provider.h \
        libide/git/ide-git-vcs.c \
        libide/git/ide-git-vcs.h \
        libide/gjs/ide-gjs-script.cpp \
@@ -156,6 +158,8 @@ libide_1_0_la_SOURCES = \
        libide/gca/ide-gca-service.h \
        libide/gca/ide-gca-service.h \
        libide/gconstructor.h \
+       libide/git/ide-git-search-index.c \
+       libide/git/ide-git-search-index.h \
        libide/ide-async-helper.c \
        libide/ide-async-helper.h \
        libide/ide-search-reducer.c \
diff --git a/libide/git/ide-git-search-index.c b/libide/git/ide-git-search-index.c
new file mode 100644
index 0000000..884793b
--- /dev/null
+++ b/libide/git/ide-git-search-index.c
@@ -0,0 +1,469 @@
+/* ide-git-search-index.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser 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 <ctype.h>
+#include <fuzzy.h>
+#include <glib/gi18n.h>
+#include <libgit2-glib/ggit.h>
+
+#include "ide-context.h"
+#include "ide-git-search-index.h"
+#include "ide-project.h"
+#include "ide-search-context.h"
+#include "ide-search-provider.h"
+#include "ide-search-reducer.h"
+#include "ide-search-result.h"
+
+struct _IdeGitSearchIndex
+{
+  IdeObject parent_instance;
+
+  GFile *location;
+  gchar *shorthand;
+  Fuzzy *fuzzy;
+};
+
+static GQuark gPathQuark;
+
+static void async_initable_iface_init (GAsyncInitableIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (IdeGitSearchIndex,
+                        ide_git_search_index,
+                        IDE_TYPE_OBJECT,
+                        0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
+                                               async_initable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_LOCATION,
+  LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+static void
+activate_cb (IdeSearchResult *result,
+             gpointer         user_data)
+{
+  g_assert (IDE_IS_SEARCH_RESULT (result));
+
+  /* TODO: Hook up document manager in LibIDE */
+}
+
+/**
+ * ide_git_search_index_get_location:
+ *
+ * Returns the location of the .git directory.
+ *
+ * Returns: (transfer none): A #GFile.
+ */
+GFile *
+ide_git_search_index_get_location (IdeGitSearchIndex *self)
+{
+  g_return_val_if_fail (IDE_IS_GIT_SEARCH_INDEX (self), NULL);
+
+  return self->location;
+}
+
+static void
+ide_git_search_index_set_location (IdeGitSearchIndex *self,
+                                   GFile             *location)
+{
+  g_return_if_fail (IDE_IS_GIT_SEARCH_INDEX (self));
+  g_return_if_fail (G_IS_FILE (location));
+
+  if (g_set_object (&self->location, location))
+    g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_LOCATION]);
+}
+
+static gchar *
+str_highlight (const gchar *str,
+               const gchar *match)
+{
+  GString *ret;
+  gunichar str_ch;
+  gunichar match_ch;
+
+  g_return_val_if_fail (str, NULL);
+  g_return_val_if_fail (match, NULL);
+
+  ret = g_string_new (NULL);
+
+  for (; *str; str = g_utf8_next_char (str))
+    {
+      str_ch = g_utf8_get_char (str);
+      match_ch = g_utf8_get_char (match);
+
+      if (str_ch == match_ch)
+        {
+          g_string_append (ret, "<u>");
+          g_string_append_unichar (ret, str_ch);
+          g_string_append (ret, "</u>");
+
+          match = g_utf8_next_char (match);
+        }
+      else
+        {
+          g_string_append_unichar (ret, str_ch);
+        }
+    }
+
+  return g_string_free (ret, FALSE);
+}
+
+static gchar *
+filter_search_terms (const gchar *search_terms)
+{
+  GString *str;
+
+  str = g_string_new (NULL);
+
+  for (; *search_terms; search_terms = g_utf8_next_char (search_terms))
+    {
+      gunichar ch = g_utf8_get_char (search_terms);
+
+      if ((isascii (ch) != 0) && !g_unichar_isspace (ch))
+        g_string_append_unichar (str, ch);
+    }
+
+  return g_string_free (str, FALSE);
+}
+
+static gchar **
+split_path (const gchar  *path,
+            gchar       **shortname)
+{
+  gchar **parts;
+  gsize len;
+
+  g_return_val_if_fail (path, NULL);
+  g_return_val_if_fail (shortname, NULL);
+
+  *shortname = NULL;
+
+  parts = g_strsplit (path, "/", 0);
+  len = g_strv_length (parts);
+
+  if (len)
+    {
+      *shortname = parts [len-1];
+      parts [len-1] = 0;
+    }
+
+  return parts;
+}
+
+void
+ide_git_search_index_populate (IdeGitSearchIndex *self,
+                               IdeSearchProvider *provider,
+                               IdeSearchContext  *search_context,
+                               gsize              max_results,
+                               const gchar       *search_terms)
+{
+  g_auto(IdeSearchReducer) reducer = { 0 };
+  g_autoptr(gchar) delimited = NULL;
+  IdeContext *context;
+  IdeProject *project;
+  const gchar *project_name;
+  GArray *matches = NULL;
+  GString *str = NULL;
+  gsize truncate_len = 0;
+  gsize i;
+
+  g_return_if_fail (IDE_IS_GIT_SEARCH_INDEX (self));
+  g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (search_context));
+  g_return_if_fail (search_terms);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+
+  /* Filter space and non-ascii from the search terms */
+  delimited = filter_search_terms (search_terms);
+
+  /* Execute the search against the fuzzy index */
+  matches = fuzzy_match (self->fuzzy, delimited, max_results);
+
+  /* Generate the prefix for the secondary text */
+  project = ide_context_get_project (context);
+  project_name = ide_project_get_name (project);
+  str = g_string_new (project_name);
+  if (self->shorthand)
+    g_string_append_printf (str, "[%s]", self->shorthand);
+  truncate_len = str->len;
+
+  /* initialize our reducer, which helps us prevent creating unnecessary
+   * objects that will simply be discarded */
+  ide_search_reducer_init (&reducer, search_context, provider);
+
+  for (i = 0; i < matches->len; i++)
+    {
+      FuzzyMatch *match = &g_array_index (matches, FuzzyMatch, i);
+
+      if (ide_search_reducer_accepts (&reducer, match->score))
+        {
+          g_autoptr(gchar) shortname = NULL;
+          g_autoptr(gchar) markup = NULL;
+          g_autoptr(IdeSearchResult) result = NULL;
+          gchar **parts;
+          gsize j;
+
+          /* truncate the secondary text to the shared info */
+          g_string_truncate (str, truncate_len);
+
+          /* Generate pretty path to the directory */
+          parts = split_path (match->value, &shortname);
+          for (j = 0; parts [j]; j++)
+            g_string_append_printf (str, " / %s", parts [j]);
+          g_strfreev (parts);
+
+          /* highlight the title string with underlines */
+          markup = str_highlight (shortname, search_terms);
+
+          /* create our search result and connect to signals */
+          result = ide_search_result_new (context,
+                                          markup,
+                                          str->str,
+                                          match->score);
+          g_object_set_qdata_full (G_OBJECT (result), gPathQuark,
+                                   g_strdup (match->value), g_free);
+#if 0
+          /* I think we might want to leave this signal on the provider */
+          g_signal_connect (result, "activate", G_CALLBACK (activate_cb), NULL);
+#endif
+
+          /* push the result through the search reducer */
+          ide_search_reducer_push (&reducer, result);
+        }
+    }
+
+cleanup:
+  g_clear_pointer (&matches, g_array_unref);
+  g_string_free (str, TRUE);
+}
+
+static void
+ide_git_search_index_finalize (GObject *object)
+{
+  IdeGitSearchIndex *self = (IdeGitSearchIndex *)object;
+
+  g_clear_object (&self->location);
+  g_clear_pointer (&self->shorthand, g_free);
+  g_clear_pointer (&self->fuzzy, fuzzy_unref);
+
+  G_OBJECT_CLASS (ide_git_search_index_parent_class)->finalize (object);
+}
+
+static void
+ide_git_search_index_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  IdeGitSearchIndex *self = IDE_GIT_SEARCH_INDEX (object);
+
+  switch (prop_id)
+    {
+    case PROP_LOCATION:
+      g_value_set_object (value, ide_git_search_index_get_location (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_git_search_index_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  IdeGitSearchIndex *self = IDE_GIT_SEARCH_INDEX (object);
+
+  switch (prop_id)
+    {
+    case PROP_LOCATION:
+      ide_git_search_index_set_location (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_git_search_index_class_init (IdeGitSearchIndexClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_git_search_index_finalize;
+  object_class->get_property = ide_git_search_index_get_property;
+  object_class->set_property = ide_git_search_index_set_property;
+
+  gPathQuark = g_quark_from_static_string ("IDE_GIT_SEARCH_INDEX_PATH");
+
+  gParamSpecs [PROP_LOCATION] =
+    g_param_spec_object ("location",
+                         _("Location"),
+                         _("The location of the .git index."),
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_LOCATION,
+                                   gParamSpecs [PROP_LOCATION]);
+}
+
+static void
+ide_git_search_index_init (IdeGitSearchIndex *self)
+{
+}
+
+static void
+ide_git_search_index_init_worker (GTask        *task,
+                                  gpointer      source_object,
+                                  gpointer      task_data,
+                                  GCancellable *cancellable)
+{
+  IdeGitSearchIndex *self = source_object;
+  GgitRepository *repository = NULL;
+  GgitIndexEntries *entries = NULL;
+  GgitIndex *index = NULL;
+  GgitRef *ref;
+  GError *error = NULL;
+  GFile *repository_dir = task_data;
+  guint count;
+  guint i;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (IDE_IS_GIT_SEARCH_INDEX (self));
+
+  if (!self->location)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_FILENAME,
+                               _("Location must be set to .git directory."));
+      goto cleanup;
+    }
+
+  repository = ggit_repository_open (self->location, &error);
+
+  if (!repository)
+    {
+      g_task_return_error (task, error);
+      goto cleanup;
+    }
+
+  ref = ggit_repository_get_head (repository, NULL);
+
+  if (ref)
+    {
+      self->shorthand = g_strdup (ggit_ref_get_shorthand (ref));
+      g_clear_object (&ref);
+    }
+
+  index = ggit_repository_get_index (repository, &error);
+
+  if (!index)
+    {
+      g_task_return_error (task, error);
+      goto cleanup;
+    }
+
+  entries = ggit_index_get_entries (index);
+
+  self->fuzzy = fuzzy_new_with_free_func (FALSE, g_free);
+  count = ggit_index_entries_size (entries);
+
+  fuzzy_begin_bulk_insert (self->fuzzy);
+
+  for (i = 0; i < count; i++)
+    {
+      GgitIndexEntry *entry;
+      const gchar *path;
+
+      entry = ggit_index_entries_get_by_index (entries, i);
+      path = ggit_index_entry_get_path (entry);
+
+      /* FIXME:
+       *
+       * fuzzy does not yet support UTF-8, which is the native format
+       * for the filesystem. It wont be as fast, but we can just take
+       * the cost of gunichar most likely.
+       */
+      if (g_str_is_ascii (path))
+        {
+          const gchar *shortname = strrchr (path, '/');
+
+          if (shortname)
+            fuzzy_insert (self->fuzzy, shortname, g_strdup (path));
+          else
+            fuzzy_insert (self->fuzzy, path, g_strdup (path));
+        }
+
+      ggit_index_entry_unref (entry);
+    }
+
+  fuzzy_end_bulk_insert (self->fuzzy);
+
+  g_task_return_boolean (task, TRUE);
+
+cleanup:
+  g_clear_pointer (&entries, ggit_index_entries_unref);
+  g_clear_object (&index);
+  g_clear_object (&repository);
+}
+
+static void
+ide_git_search_index_init_async (GAsyncInitable      *initable,
+                                 gint                 io_priority,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+  IdeGitSearchIndex *self = (IdeGitSearchIndex *)initable;
+  g_autoptr(GTask) task = NULL;
+
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (IDE_IS_GIT_SEARCH_INDEX (self));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_run_in_thread (task, ide_git_search_index_init_worker);
+}
+
+static gboolean
+ide_git_search_index_init_finish (GAsyncInitable  *initable,
+                                  GAsyncResult    *result,
+                                  GError         **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (IDE_IS_GIT_SEARCH_INDEX (initable), FALSE);
+  g_return_val_if_fail (G_IS_TASK (task), FALSE);
+
+  return g_task_propagate_boolean (task, error);
+}
+
+static void
+async_initable_iface_init (GAsyncInitableIface *iface)
+{
+  iface->init_async = ide_git_search_index_init_async;
+  iface->init_finish = ide_git_search_index_init_finish;
+}
diff --git a/libide/git/ide-git-search-index.h b/libide/git/ide-git-search-index.h
new file mode 100644
index 0000000..28820f1
--- /dev/null
+++ b/libide/git/ide-git-search-index.h
@@ -0,0 +1,39 @@
+/* ide-git-search-index.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser 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_GIT_SEARCH_INDEX_H
+#define IDE_GIT_SEARCH_INDEX_H
+
+#include "ide-object.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_GIT_SEARCH_INDEX (ide_git_search_index_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeGitSearchIndex, ide_git_search_index,
+                      IDE, GIT_SEARCH_INDEX, IdeObject)
+
+void ide_git_search_index_populate (IdeGitSearchIndex *self,
+                                    IdeSearchProvider *provider,
+                                    IdeSearchContext  *context,
+                                    gsize              max_results,
+                                    const gchar       *search_terms);
+
+G_END_DECLS
+
+#endif /* IDE_GIT_SEARCH_INDEX_H */
diff --git a/libide/git/ide-git-search-provider.c b/libide/git/ide-git-search-provider.c
new file mode 100644
index 0000000..8778b31
--- /dev/null
+++ b/libide/git/ide-git-search-provider.c
@@ -0,0 +1,215 @@
+/* ide-git-search-provider.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser 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-context.h"
+#include "ide-git-search-index.h"
+#include "ide-git-search-provider.h"
+#include "ide-git-vcs.h"
+#include "ide-search-context.h"
+
+struct _IdeGitSearchProvider
+{
+  IdeSearchProvider  parent_instance;
+
+  IdeGitSearchIndex *index;
+};
+
+typedef struct
+{
+  IdeSearchContext *context;
+  gchar            *search_terms;
+  gsize             max_results;
+} PopulateState;
+
+G_DEFINE_TYPE (IdeGitSearchProvider, ide_git_search_provider,
+               IDE_TYPE_SEARCH_PROVIDER)
+
+static void
+ide_git_search_provider_get_index_cb (GObject      *object,
+                                      GAsyncResult *result,
+                                      gpointer      user_data)
+{
+  g_autoptr(GTask) task = user_data;
+  GAsyncInitable *initable = (GAsyncInitable *)object;
+  IdeGitSearchProvider *self;
+  g_autoptr(GObject) res = NULL;
+  GError *error = NULL;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (G_IS_ASYNC_RESULT (result));
+
+  self = g_task_get_source_object (task);
+
+  res = g_async_initable_new_finish (initable, result, &error);
+
+  if (!res)
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  g_clear_object (&self->index);
+  self->index = g_object_ref (res);
+
+  g_task_return_pointer (task, g_object_ref (self->index), g_object_unref);
+}
+
+static void
+ide_git_search_provider_get_index_async (IdeGitSearchProvider *self,
+                                         GCancellable         *cancellable,
+                                         GAsyncReadyCallback   callback,
+                                         gpointer              user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  g_autoptr(GFile) location = NULL;
+  GgitRepository *repository;
+  IdeContext *context;
+  IdeVcs *vcs;
+
+  g_return_if_fail (IDE_IS_GIT_SEARCH_PROVIDER (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+
+  if (self->index)
+    {
+      g_task_return_pointer (task, g_object_ref (self->index), g_object_unref);
+      return;
+    }
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+
+  if (!IDE_IS_GIT_VCS (vcs))
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_SUPPORTED,
+                               _("Git search provider requires the Git VCS"));
+      return;
+    }
+
+  repository = ide_git_vcs_get_repository (IDE_GIT_VCS (vcs));
+  location = ggit_repository_get_location (repository);
+
+  g_async_initable_new_async (IDE_TYPE_GIT_SEARCH_INDEX,
+                              G_PRIORITY_DEFAULT,
+                              cancellable,
+                              ide_git_search_provider_get_index_cb,
+                              g_object_ref (task),
+                              "context", context,
+                              "location", location,
+                              NULL);
+}
+
+static IdeGitSearchIndex *
+ide_git_search_provider_get_index_finish (IdeGitSearchProvider  *self,
+                                          GAsyncResult          *result,
+                                          GError               **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (IDE_IS_GIT_SEARCH_PROVIDER (self), NULL);
+  g_return_val_if_fail (G_IS_TASK (task), NULL);
+
+  return g_task_propagate_pointer (task, error);
+}
+
+static void
+populate_get_index_cb (GObject      *object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
+{
+  IdeGitSearchProvider *self = (IdeGitSearchProvider *)object;
+  PopulateState *state = user_data;
+  g_autoptr(IdeGitSearchIndex) index = NULL;
+  GError *error = NULL;
+
+  index = ide_git_search_provider_get_index_finish (self, result, &error);
+
+  if (index)
+    {
+      ide_git_search_index_populate (index,
+                                     IDE_SEARCH_PROVIDER (self),
+                                     state->context,
+                                     state->max_results,
+                                     state->search_terms);
+    }
+
+cleanup:
+  ide_search_context_provider_completed (state->context,
+                                         IDE_SEARCH_PROVIDER (self));
+
+  g_free (state->search_terms);
+  g_object_unref (state->context);
+  g_slice_free (PopulateState, state);
+}
+
+static void
+ide_git_search_provider_populate (IdeSearchProvider *provider,
+                                  IdeSearchContext  *context,
+                                  const gchar       *search_terms,
+                                  gsize              max_results,
+                                  GCancellable      *cancellable)
+{
+  IdeGitSearchProvider *self = (IdeGitSearchProvider *)provider;
+  PopulateState *state;
+
+  g_return_if_fail (IDE_IS_GIT_SEARCH_PROVIDER (self));
+  g_return_if_fail (IDE_IS_SEARCH_CONTEXT (context));
+  g_return_if_fail (search_terms);
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  state = g_slice_new0 (PopulateState);
+  state->context = g_object_ref (context);
+  state->search_terms = g_strdup (search_terms);
+  state->max_results = max_results;
+
+  ide_git_search_provider_get_index_async (self,
+                                           cancellable,
+                                           populate_get_index_cb,
+                                           state);
+}
+
+static void
+ide_git_search_provider_finalize (GObject *object)
+{
+  IdeGitSearchProvider *self = (IdeGitSearchProvider *)object;
+
+  g_clear_object (&self->index);
+
+  G_OBJECT_CLASS (ide_git_search_provider_parent_class)->finalize (object);
+}
+
+static void
+ide_git_search_provider_class_init (IdeGitSearchProviderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeSearchProviderClass *provider_class = IDE_SEARCH_PROVIDER_CLASS (klass);
+
+  object_class->finalize = ide_git_search_provider_finalize;
+
+  provider_class->populate = ide_git_search_provider_populate;
+}
+
+static void
+ide_git_search_provider_init (IdeGitSearchProvider *self)
+{
+}
diff --git a/libide/git/ide-git-search-provider.h b/libide/git/ide-git-search-provider.h
new file mode 100644
index 0000000..0b6cc8e
--- /dev/null
+++ b/libide/git/ide-git-search-provider.h
@@ -0,0 +1,35 @@
+/* ide-git-search-provider.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser 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_GIT_SEARCH_PROVIDER_H
+#define IDE_GIT_SEARCH_PROVIDER_H
+
+#include "ide-search-provider.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_GIT_SEARCH_PROVIDER (ide_git_search_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeGitSearchProvider,
+                      ide_git_search_provider,
+                      IDE, GIT_SEARCH_PROVIDER,
+                      IdeSearchProvider)
+
+G_END_DECLS
+
+#endif /* IDE_GIT_SEARCH_PROVIDER_H */
diff --git a/libide/ide.c b/libide/ide.c
index ea360d5..dd12183 100644
--- a/libide/ide.c
+++ b/libide/ide.c
@@ -30,6 +30,7 @@
 #include "ide-editorconfig-file-settings.h"
 #include "ide-file-settings.h"
 #include "ide-gca-service.h"
+#include "ide-git-search-provider.h"
 #include "ide-git-vcs.h"
 #include "ide-gjs-script.h"
 #include "ide-gsettings-file-settings.h"
@@ -101,6 +102,11 @@ ide_init_ctor (void)
                                   IDE_SCRIPT_EXTENSION_POINT".gjs",
                                   -100);
 
+  g_io_extension_point_implement (IDE_SEARCH_PROVIDER_EXTENSION_POINT,
+                                  IDE_TYPE_GIT_SEARCH_PROVIDER,
+                                  IDE_SEARCH_PROVIDER_EXTENSION_POINT".git",
+                                  -100);
+
   g_io_extension_point_implement (IDE_SERVICE_EXTENSION_POINT,
                                   IDE_TYPE_CLANG_SERVICE,
                                   IDE_SERVICE_EXTENSION_POINT".clang",


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