[gnome-builder/wip/gtk4-port: 985/1774] libide/projects: add similar file locator interface




commit e927460c2bbe32593799c2b78958028293dc0271
Author: Christian Hergert <chergert redhat com>
Date:   Wed May 11 15:44:42 2022 -0700

    libide/projects: add similar file locator interface
    
    This will be used to implement "find other files" in a more extensible way.
    The find-other-files plugin will be able to reuse this from the project
    object and then attach it to various widgetry when necessary.

 src/libide/projects/ide-project.c              | 176 ++++++++++++++++++++++++-
 src/libide/projects/ide-project.h              |  54 ++++----
 src/libide/projects/ide-similar-file-locator.c |  89 +++++++++++++
 src/libide/projects/ide-similar-file-locator.h |  59 +++++++++
 src/libide/projects/libide-projects.h          |   1 +
 src/libide/projects/meson.build                |   2 +
 6 files changed, 358 insertions(+), 23 deletions(-)
---
diff --git a/src/libide/projects/ide-project.c b/src/libide/projects/ide-project.c
index e3fb7cd78..54f720619 100644
--- a/src/libide/projects/ide-project.c
+++ b/src/libide/projects/ide-project.c
@@ -23,15 +23,20 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#include <libpeas/peas.h>
+
 #include <libide-code.h>
+#include <libide-plugins.h>
 
 #include "ide-buffer-private.h"
 
 #include "ide-project.h"
+#include "ide-similar-file-locator.h"
 
 struct _IdeProject
 {
-  IdeObject parent_instance;
+  IdeObject               parent_instance;
+  IdeExtensionSetAdapter *similar_file_locators;
 };
 
 typedef struct
@@ -51,9 +56,23 @@ G_DEFINE_FINAL_TYPE (IdeProject, ide_project, IDE_TYPE_OBJECT)
 
 static guint signals [N_SIGNALS];
 
+static void
+ide_project_dispose (GObject *object)
+{
+  IdeProject *self = (IdeProject *)object;
+
+  ide_clear_and_destroy_object (&self->similar_file_locators);
+
+  G_OBJECT_CLASS (ide_project_parent_class)->dispose (object);
+}
+
 static void
 ide_project_class_init (IdeProjectClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_project_dispose;
+
   signals [FILE_RENAMED] =
     g_signal_new ("file-renamed",
                   G_TYPE_FROM_CLASS (klass),
@@ -484,3 +503,158 @@ ide_project_trash_file_finish (IdeProject    *self,
 
   IDE_RETURN (ret);
 }
+
+typedef struct
+{
+  GFile *file;
+  GListStore *models;
+  guint n_active;
+} ListSimilar;
+
+static void
+list_similar_free (ListSimilar *state)
+{
+  g_assert (state->n_active == 0);
+
+  g_clear_object (&state->file);
+  g_clear_object (&state->models);
+  g_slice_free (ListSimilar, state);
+}
+
+static void
+ide_project_list_similar_cb (GObject      *object,
+                             GAsyncResult *result,
+                             gpointer      user_data)
+{
+  IdeSimilarFileLocator *locator = (IdeSimilarFileLocator *)object;
+  g_autoptr(GListModel) model = NULL;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  ListSimilar *state;
+  IdeProject *self;
+
+  g_assert (IDE_IS_SIMILAR_FILE_LOCATOR (locator));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  self = ide_task_get_source_object (task);
+  state = ide_task_get_task_data (task);
+
+  g_assert (IDE_IS_PROJECT (self));
+  g_assert (state != NULL);
+  g_assert (G_IS_FILE (state->file));
+  g_assert (G_IS_LIST_STORE (state->models));
+
+  if ((model = ide_similar_file_locator_list_finish (locator, result, &error)))
+    g_list_store_append (state->models, model);
+  else if (!ide_error_ignore (error))
+    ide_object_warning (IDE_OBJECT (self), "%s", error->message);
+
+  state->n_active--;
+
+  if (state->n_active == 0)
+    ide_task_return_object (task,
+                            gtk_flatten_list_model_new (g_object_ref (G_LIST_MODEL (state->models))));
+}
+
+static void
+ide_project_list_similar_foreach_cb (IdeExtensionSetAdapter *set,
+                                     PeasPluginInfo         *plugin_info,
+                                     PeasExtension          *exten,
+                                     gpointer                user_data)
+{
+  IdeSimilarFileLocator *locator = (IdeSimilarFileLocator *)exten;
+  IdeTask *task = user_data;
+  ListSimilar *state;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_SIMILAR_FILE_LOCATOR (locator));
+  g_assert (IDE_IS_TASK (task));
+
+  state = ide_task_get_task_data (task);
+
+  g_assert (state != NULL);
+  g_assert (G_IS_FILE (state->file));
+  g_assert (G_IS_LIST_STORE (state->models));
+
+  state->n_active++;
+
+  ide_similar_file_locator_list_async (locator,
+                                       state->file,
+                                       ide_task_get_cancellable (task),
+                                       ide_project_list_similar_cb,
+                                       g_object_ref (task));
+}
+
+void
+ide_project_list_similar_async (IdeProject          *self,
+                                GFile               *file,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+  ListSimilar *state;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_MAIN_THREAD ());
+  g_return_if_fail (IDE_IS_PROJECT (self));
+  g_return_if_fail (G_IS_FILE (file));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, ide_project_list_similar_async);
+
+  if (self->similar_file_locators == NULL)
+    self->similar_file_locators = ide_extension_set_adapter_new (IDE_OBJECT (self),
+                                                                 peas_engine_get_default (),
+                                                                 IDE_TYPE_SIMILAR_FILE_LOCATOR,
+                                                                 NULL, NULL);
+
+  state = g_slice_new0 (ListSimilar);
+  state->file = g_object_ref (file);
+  state->models = g_list_store_new (G_TYPE_LIST_MODEL);
+  ide_task_set_task_data (task, state, list_similar_free);
+
+  ide_extension_set_adapter_foreach (self->similar_file_locators,
+                                     ide_project_list_similar_foreach_cb,
+                                     task);
+
+  if (state->n_active == 0)
+    ide_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_SUPPORTED,
+                               "Not supported");
+
+  IDE_EXIT;
+}
+
+/**
+ * ide_project_list_similar_finish:
+ * @self: a #IdeProject
+ * @result: a #GAsyncResult
+ * @error: location for a #GError
+ *
+ * Completes asynchronous request to locate similar files.
+ *
+ * Returns: (transfer full): a #GListModel of #GFile or %NULL
+ */
+GListModel *
+ide_project_list_similar_finish (IdeProject    *self,
+                                 GAsyncResult  *result,
+                                 GError       **error)
+{
+  GListModel *ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
+  g_return_val_if_fail (IDE_IS_PROJECT (self), NULL);
+  g_return_val_if_fail (IDE_IS_TASK (result), NULL);
+
+  ret = ide_task_propagate_object (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
diff --git a/src/libide/projects/ide-project.h b/src/libide/projects/ide-project.h
index 156a04250..f5f480416 100644
--- a/src/libide/projects/ide-project.h
+++ b/src/libide/projects/ide-project.h
@@ -30,27 +30,37 @@ IDE_AVAILABLE_IN_ALL
 G_DECLARE_FINAL_TYPE (IdeProject, ide_project, IDE, PROJECT, IdeObject)
 
 IDE_AVAILABLE_IN_ALL
-IdeProject *ide_project_from_context       (IdeContext           *context);
-IDE_AVAILABLE_IN_ALL
-void        ide_project_rename_file_async  (IdeProject           *self,
-                                            GFile                *orig_file,
-                                            GFile                *new_file,
-                                            GCancellable         *cancellable,
-                                            GAsyncReadyCallback   callback,
-                                            gpointer              user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean    ide_project_rename_file_finish (IdeProject           *self,
-                                            GAsyncResult         *result,
-                                            GError              **error);
-IDE_AVAILABLE_IN_ALL
-void        ide_project_trash_file_async   (IdeProject           *self,
-                                            GFile                *file,
-                                            GCancellable         *cancellable,
-                                            GAsyncReadyCallback   callback,
-                                            gpointer              user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean    ide_project_trash_file_finish  (IdeProject           *self,
-                                            GAsyncResult         *result,
-                                            GError              **error);
+IdeProject *ide_project_from_context         (IdeContext           *context);
+IDE_AVAILABLE_IN_ALL
+void        ide_project_rename_file_async    (IdeProject           *self,
+                                              GFile                *orig_file,
+                                              GFile                *new_file,
+                                              GCancellable         *cancellable,
+                                              GAsyncReadyCallback   callback,
+                                              gpointer              user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean    ide_project_rename_file_finish   (IdeProject           *self,
+                                              GAsyncResult         *result,
+                                              GError              **error);
+IDE_AVAILABLE_IN_ALL
+void        ide_project_trash_file_async     (IdeProject           *self,
+                                              GFile                *file,
+                                              GCancellable         *cancellable,
+                                              GAsyncReadyCallback   callback,
+                                              gpointer              user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean    ide_project_trash_file_finish    (IdeProject           *self,
+                                              GAsyncResult         *result,
+                                              GError              **error);
+IDE_AVAILABLE_IN_ALL
+void         ide_project_list_similar_async  (IdeProject           *self,
+                                              GFile                *file,
+                                              GCancellable         *cancellable,
+                                              GAsyncReadyCallback   callback,
+                                              gpointer              user_data);
+IDE_AVAILABLE_IN_ALL
+GListModel  *ide_project_list_similar_finish (IdeProject           *self,
+                                              GAsyncResult         *result,
+                                              GError              **error);
 
 G_END_DECLS
diff --git a/src/libide/projects/ide-similar-file-locator.c b/src/libide/projects/ide-similar-file-locator.c
new file mode 100644
index 000000000..35dca9969
--- /dev/null
+++ b/src/libide/projects/ide-similar-file-locator.c
@@ -0,0 +1,89 @@
+/* ide-similar-file-locator.c
+ *
+ * Copyright 2022 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 "ide-similar-file-locator"
+
+#include "config.h"
+
+#include "ide-similar-file-locator.h"
+
+G_DEFINE_INTERFACE (IdeSimilarFileLocator, ide_similar_file_locator, G_TYPE_OBJECT)
+
+static void
+ide_similar_file_locator_default_init (IdeSimilarFileLocatorInterface *iface)
+{
+}
+
+/**
+ * ide_similar_file_locator_list_async:
+ * @self: a #IdeSimilarFileLocator
+ * @file: a #GFile to find similar files for
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: callback to use to complete operation
+ * @user_data: closure data for @callback
+ *
+ * Asynchronously requests locating similar files.
+ *
+ * A similar file may be found such as those with similar file suffixes
+ * or perhaps a designer file associated with a source file.
+ */
+void
+ide_similar_file_locator_list_async (IdeSimilarFileLocator *self,
+                                     GFile                 *file,
+                                     GCancellable          *cancellable,
+                                     GAsyncReadyCallback    callback,
+                                     gpointer               user_data)
+{
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_SIMILAR_FILE_LOCATOR (self));
+  g_return_if_fail (G_IS_FILE (file));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  IDE_SIMILAR_FILE_LOCATOR_GET_IFACE (self)->list_async (self, file, cancellable, callback, user_data);
+
+  IDE_EXIT;
+}
+
+/**
+ * ide_similar_file_locator_list_finish:
+ * @self: a #IdeSimilarFileLocator
+ * @result: a #GAsyncResult
+ * @error: location for a #GError, or %NULL
+ *
+ * Completes asynchronous request to list similar files.
+ *
+ * Returns: (transfer full): a #GListModel of #GFile or %NULL
+ */
+GListModel *
+ide_similar_file_locator_list_finish (IdeSimilarFileLocator  *self,
+                                      GAsyncResult           *result,
+                                      GError                **error)
+{
+  GListModel *ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_SIMILAR_FILE_LOCATOR (self), NULL);
+
+  ret = IDE_SIMILAR_FILE_LOCATOR_GET_IFACE (self)->list_finish (self, result, error);
+
+  IDE_RETURN (ret);
+}
diff --git a/src/libide/projects/ide-similar-file-locator.h b/src/libide/projects/ide-similar-file-locator.h
new file mode 100644
index 000000000..6b955b0fc
--- /dev/null
+++ b/src/libide/projects/ide-similar-file-locator.h
@@ -0,0 +1,59 @@
+/* ide-similar-file-locator.h
+ *
+ * Copyright 2022 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
+
+#if !defined (IDE_PROJECTS_INSIDE) && !defined (IDE_PROJECTS_COMPILATION)
+# error "Only <libide-projects.h> can be included directly."
+#endif
+
+#include <libide-core.h>
+
+#define IDE_TYPE_SIMILAR_FILE_LOCATOR (ide_similar_file_locator_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_INTERFACE (IdeSimilarFileLocator, ide_similar_file_locator, IDE, SIMILAR_FILE_LOCATOR, GObject)
+
+struct _IdeSimilarFileLocatorInterface
+{
+  GTypeInterface parent_iface;
+
+  void        (*list_async)  (IdeSimilarFileLocator  *self,
+                              GFile                  *file,
+                              GCancellable           *cancellable,
+                              GAsyncReadyCallback     callback,
+                              gpointer                user_data);
+  GListModel *(*list_finish) (IdeSimilarFileLocator  *self,
+                              GAsyncResult           *result,
+                              GError                **error);
+};
+
+IDE_AVAILABLE_IN_ALL
+void        ide_similar_file_locator_list_async  (IdeSimilarFileLocator  *self,
+                                                  GFile                  *file,
+                                                  GCancellable           *cancellable,
+                                                  GAsyncReadyCallback     callback,
+                                                  gpointer                user_data);
+IDE_AVAILABLE_IN_ALL
+GListModel *ide_similar_file_locator_list_finish (IdeSimilarFileLocator  *self,
+                                                  GAsyncResult           *result,
+                                                  GError                **error);
+
+G_END_DECLS
diff --git a/src/libide/projects/libide-projects.h b/src/libide/projects/libide-projects.h
index f1f7db00d..62e1cfc75 100644
--- a/src/libide/projects/libide-projects.h
+++ b/src/libide/projects/libide-projects.h
@@ -34,6 +34,7 @@
 #include "ide-project-tree-addin.h"
 #include "ide-projects-global.h"
 #include "ide-recent-projects.h"
+#include "ide-similar-file-locator.h"
 #include "ide-template-base.h"
 #include "ide-template-provider.h"
 
diff --git a/src/libide/projects/meson.build b/src/libide/projects/meson.build
index 0916891d1..e4c36399d 100644
--- a/src/libide/projects/meson.build
+++ b/src/libide/projects/meson.build
@@ -15,6 +15,7 @@ libide_projects_public_headers = [
   'ide-project-template.h',
   'ide-project-tree-addin.h',
   'ide-recent-projects.h',
+  'ide-similar-file-locator.h',
   'ide-template-base.h',
   'ide-template-provider.h',
   'libide-projects.h',
@@ -43,6 +44,7 @@ libide_projects_public_sources = [
   'ide-project-template.c',
   'ide-project-tree-addin.c',
   'ide-recent-projects.c',
+  'ide-similar-file-locator.c',
   'ide-template-base.c',
   'ide-template-provider.c',
 ]


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