[gnome-builder] symbol-tree: make IdeSymbolNode location resolver async



commit b9e2239d536c830a5a0220959a8010e4d48afdda
Author: Christian Hergert <chergert redhat com>
Date:   Tue Oct 18 22:52:59 2016 -0700

    symbol-tree: make IdeSymbolNode location resolver async
    
    This changes IdeSymbolNode::get_location() to be asynchronous using
    IdeSymbolNode::get_location_async() and ::get_location_finish(). This
    breaks ABI, but we are the only consumers of this API currently so it's
    fine.

 libide/symbols/ide-symbol-node.c            |   48 +++++++++++++++++---
 libide/symbols/ide-symbol-node.h            |   22 +++++++--
 plugins/clang/ide-clang-symbol-node.c       |   29 ++++++++++--
 plugins/ctags/ide-ctags-symbol-node.c       |   65 +++++++++++++++------------
 plugins/symbol-tree/symbol-tree-builder.c   |   57 ++++++++++++++++++-----
 plugins/vala-pack/ide-vala-symbol-tree.vala |    2 +-
 6 files changed, 163 insertions(+), 60 deletions(-)
---
diff --git a/libide/symbols/ide-symbol-node.c b/libide/symbols/ide-symbol-node.c
index aef8508..8a22bc2 100644
--- a/libide/symbols/ide-symbol-node.c
+++ b/libide/symbols/ide-symbol-node.c
@@ -41,10 +41,28 @@ enum {
 
 static GParamSpec *properties [LAST_PROP];
 
+static void
+ide_symbol_node_real_get_location_async (IdeSymbolNode       *self,
+                                         GCancellable        *cancellable,
+                                         GAsyncReadyCallback  callback,
+                                         gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, ide_symbol_node_get_location_async);
+  g_task_return_new_error (task,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "Unsupported operation on symbol node");
+}
+
 static IdeSourceLocation *
-ide_symbol_node_real_get_location (IdeSymbolNode *self)
+ide_symbol_node_real_get_location_finish (IdeSymbolNode  *self,
+                                          GAsyncResult   *result,
+                                          GError        **error)
 {
-  return NULL;
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -119,7 +137,8 @@ ide_symbol_node_class_init (IdeSymbolNodeClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  klass->get_location = ide_symbol_node_real_get_location;
+  klass->get_location_async = ide_symbol_node_real_get_location_async;
+  klass->get_location_finish = ide_symbol_node_real_get_location_finish;
 
   object_class->finalize = ide_symbol_node_finalize;
   object_class->get_property = ide_symbol_node_get_property;
@@ -186,17 +205,32 @@ ide_symbol_node_get_kind (IdeSymbolNode *self)
   return priv->kind;
 }
 
+void
+ide_symbol_node_get_location_async (IdeSymbolNode       *self,
+                                    GCancellable        *cancellable,
+                                    GAsyncReadyCallback  callback,
+                                    gpointer             user_data)
+{
+  g_return_if_fail (IDE_IS_SYMBOL_NODE (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  IDE_SYMBOL_NODE_GET_CLASS (self)->get_location_async (self, cancellable, callback, user_data);
+}
+
 /**
- * ide_symbol_node_get_location:
+ * ide_symbol_node_get_location_finish:
  *
- * Gets the location for the symbol node.
+ * Completes the request to gets the location for the symbol node.
  *
  * Returns: (transfer full) (nullable): An #IdeSourceLocation or %NULL.
  */
 IdeSourceLocation *
-ide_symbol_node_get_location (IdeSymbolNode *self)
+ide_symbol_node_get_location_finish (IdeSymbolNode  *self,
+                                     GAsyncResult   *result,
+                                     GError        **error)
 {
   g_return_val_if_fail (IDE_IS_SYMBOL_NODE (self), NULL);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
 
-  return IDE_SYMBOL_NODE_GET_CLASS (self)->get_location (self);
+  return IDE_SYMBOL_NODE_GET_CLASS (self)->get_location_finish (self, result, error);
 }
diff --git a/libide/symbols/ide-symbol-node.h b/libide/symbols/ide-symbol-node.h
index 361a25a..892f0f7 100644
--- a/libide/symbols/ide-symbol-node.h
+++ b/libide/symbols/ide-symbol-node.h
@@ -34,7 +34,13 @@ struct _IdeSymbolNodeClass
 {
   IdeObjectClass parent;
 
-  IdeSourceLocation *(*get_location) (IdeSymbolNode *self);
+  void               (*get_location_async)  (IdeSymbolNode        *self,
+                                             GCancellable         *cancellable,
+                                             GAsyncReadyCallback   callback,
+                                             gpointer              user_data);
+  IdeSourceLocation *(*get_location_finish) (IdeSymbolNode        *self,
+                                             GAsyncResult         *result,
+                                             GError             **error);
 
   gpointer _reserved1;
   gpointer _reserved2;
@@ -46,10 +52,16 @@ struct _IdeSymbolNodeClass
   gpointer _reserved8;
 };
 
-IdeSymbolKind      ide_symbol_node_get_kind     (IdeSymbolNode *self);
-IdeSymbolFlags     ide_symbol_node_get_flags    (IdeSymbolNode *self);
-const gchar       *ide_symbol_node_get_name     (IdeSymbolNode *self);
-IdeSourceLocation *ide_symbol_node_get_location (IdeSymbolNode *self);
+IdeSymbolKind      ide_symbol_node_get_kind            (IdeSymbolNode        *self);
+IdeSymbolFlags     ide_symbol_node_get_flags           (IdeSymbolNode        *self);
+const gchar       *ide_symbol_node_get_name            (IdeSymbolNode        *self);
+void              ide_symbol_node_get_location_async   (IdeSymbolNode        *self,
+                                                        GCancellable         *cancellable,
+                                                        GAsyncReadyCallback   callback,
+                                                        gpointer              user_data);
+IdeSourceLocation *ide_symbol_node_get_location_finish (IdeSymbolNode        *self,
+                                                         GAsyncResult        *result,
+                                                         GError             **error);
 
 G_END_DECLS
 
diff --git a/plugins/clang/ide-clang-symbol-node.c b/plugins/clang/ide-clang-symbol-node.c
index f024e1a..f9e38a5 100644
--- a/plugins/clang/ide-clang-symbol-node.c
+++ b/plugins/clang/ide-clang-symbol-node.c
@@ -164,8 +164,11 @@ _ide_clang_symbol_node_get_cursor (IdeClangSymbolNode *self)
   return self->cursor;
 }
 
-static IdeSourceLocation *
-ide_clang_symbol_node_get_location (IdeSymbolNode *symbol_node)
+static void
+ide_clang_symbol_node_get_location_async (IdeSymbolNode       *symbol_node,
+                                          GCancellable        *cancellable,
+                                          GAsyncReadyCallback  callback,
+                                          gpointer             user_data)
 {
   IdeClangSymbolNode *self = (IdeClangSymbolNode *)symbol_node;
   IdeSourceLocation *ret;
@@ -178,8 +181,12 @@ ide_clang_symbol_node_get_location (IdeSymbolNode *symbol_node)
   IdeFile *ifile;
   guint line = 0;
   guint line_offset = 0;
+  g_autoptr(GTask) task = NULL;
 
-  g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_NODE (self), NULL);
+  g_return_if_fail (IDE_IS_CLANG_SYMBOL_NODE (self));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, ide_clang_symbol_node_get_location_async);
 
   cxloc = clang_getCursorLocation (self->cursor);
   clang_getFileLocation (cxloc, &file, &line, &line_offset, NULL);
@@ -203,7 +210,18 @@ ide_clang_symbol_node_get_location (IdeSymbolNode *symbol_node)
   g_clear_object (&gfile);
   clang_disposeString (cxfilename);
 
-  return ret;
+  g_task_return_pointer (task, ret, (GDestroyNotify)ide_source_location_unref);
+}
+
+static IdeSourceLocation *
+ide_clang_symbol_node_get_location_finish (IdeSymbolNode  *symbol_node,
+                                           GAsyncResult   *result,
+                                           GError        **error)
+{
+  g_return_val_if_fail (IDE_IS_CLANG_SYMBOL_NODE (symbol_node), NULL);
+  g_return_val_if_fail (G_IS_TASK (result), NULL);
+
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -211,7 +229,8 @@ ide_clang_symbol_node_class_init (IdeClangSymbolNodeClass *klass)
 {
   IdeSymbolNodeClass *node_class = IDE_SYMBOL_NODE_CLASS (klass);
 
-  node_class->get_location = ide_clang_symbol_node_get_location;
+  node_class->get_location_async = ide_clang_symbol_node_get_location_async;
+  node_class->get_location_finish = ide_clang_symbol_node_get_location_finish;
 }
 
 static void
diff --git a/plugins/ctags/ide-ctags-symbol-node.c b/plugins/ctags/ide-ctags-symbol-node.c
index 97ad7cd..7232ce3 100644
--- a/plugins/ctags/ide-ctags-symbol-node.c
+++ b/plugins/ctags/ide-ctags-symbol-node.c
@@ -29,56 +29,62 @@ struct _IdeCtagsSymbolNode
   GPtrArray                *children;
 };
 
-typedef struct
-{
-  IdeSourceLocation *loc;
-  gboolean done;
-} Completion;
-
 G_DEFINE_TYPE (IdeCtagsSymbolNode, ide_ctags_symbol_node, IDE_TYPE_SYMBOL_NODE)
 
 static void
-handle_location_cb (GObject      *object,
-                    GAsyncResult *result,
-                    gpointer      user_data)
+ide_ctags_symbol_node_get_location_cb (GObject      *object,
+                                       GAsyncResult *result,
+                                       gpointer      user_data)
 {
   IdeCtagsSymbolResolver *resolver = (IdeCtagsSymbolResolver *)object;
-  Completion *comp = user_data;
+  g_autoptr(IdeSourceLocation) location = NULL;
+  g_autoptr(GTask) task = user_data;
   g_autoptr(GError) error = NULL;
 
   g_assert (IDE_IS_CTAGS_SYMBOL_RESOLVER (resolver));
-  g_assert (comp != NULL);
-  g_assert (comp->loc == NULL);
-  g_assert (comp->done == FALSE);
+  g_assert (G_IS_TASK (task));
 
-  comp->loc = ide_ctags_symbol_resolver_get_location_finish (resolver, result, &error);
-  comp->done = TRUE;
+  location = ide_ctags_symbol_resolver_get_location_finish (resolver, result, &error);
 
-  if (error != NULL)
-    g_warning ("%s", error->message);
+  if (location == NULL)
+    g_task_return_error (task, g_steal_pointer (&error));
+  else
+    g_task_return_pointer (task,
+                           g_steal_pointer (&location),
+                           (GDestroyNotify)ide_source_location_unref);
 }
 
-static IdeSourceLocation *
-ide_ctags_symbol_node_get_location (IdeSymbolNode *node)
+static void
+ide_ctags_symbol_node_get_location_async (IdeSymbolNode       *node,
+                                          GCancellable        *cancellable,
+                                          GAsyncReadyCallback  callback,
+                                          gpointer             user_data)
 {
   IdeCtagsSymbolNode *self = (IdeCtagsSymbolNode *)node;
-  Completion comp = { 0 };
+  g_autoptr(GTask) task = NULL;
 
-  g_return_val_if_fail (IDE_IS_CTAGS_SYMBOL_NODE (self), NULL);
+  g_return_if_fail (IDE_IS_CTAGS_SYMBOL_NODE (self));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, ide_ctags_symbol_node_get_location_async);
 
   ide_ctags_symbol_resolver_get_location_async (self->resolver,
                                                 self->index,
                                                 self->entry,
                                                 NULL,
-                                                handle_location_cb,
-                                                &comp);
-
-  /* XXX: FIXME: TODO: ULTRA: Hack until we add async get_location() API */
+                                                ide_ctags_symbol_node_get_location_cb,
+                                                g_steal_pointer (&task));
+}
 
-  while (!comp.done)
-    gtk_main_iteration ();
+static IdeSourceLocation *
+ide_ctags_symbol_node_get_location_finish (IdeSymbolNode  *node,
+                                           GAsyncResult   *result,
+                                           GError        **error)
+{
+  g_return_val_if_fail (IDE_IS_CTAGS_SYMBOL_NODE (node), NULL);
+  g_return_val_if_fail (G_IS_TASK (result), NULL);
 
-  return comp.loc;
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
@@ -101,7 +107,8 @@ ide_ctags_symbol_node_class_init (IdeCtagsSymbolNodeClass *klass)
 
   object_class->finalize = ide_ctags_symbol_node_finalize;
 
-  symbol_node_class->get_location = ide_ctags_symbol_node_get_location;
+  symbol_node_class->get_location_async = ide_ctags_symbol_node_get_location_async;
+  symbol_node_class->get_location_finish = ide_ctags_symbol_node_get_location_finish;
 }
 
 static void
diff --git a/plugins/symbol-tree/symbol-tree-builder.c b/plugins/symbol-tree/symbol-tree-builder.c
index 1977d67..e0e2a60 100644
--- a/plugins/symbol-tree/symbol-tree-builder.c
+++ b/plugins/symbol-tree/symbol-tree-builder.c
@@ -16,6 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#define G_LOG_DOMAIN "symbol-tree-builder"
+
 #include <glib/gi18n.h>
 #include <ide.h>
 
@@ -123,40 +125,69 @@ symbol_tree_builder_build_node (IdeTreeBuilder *builder,
     }
 }
 
-static gboolean
-symbol_tree_builder_node_activated (IdeTreeBuilder *builder,
-                                    IdeTreeNode    *node)
+static void
+symbol_tree_builder_get_location_cb (GObject      *object,
+                                     GAsyncResult *result,
+                                     gpointer      user_data)
 {
-  SymbolTreeBuilder *self = (SymbolTreeBuilder *)builder;
+  IdeSymbolNode *node = (IdeSymbolNode *)object;
+  g_autoptr(SymbolTreeBuilder) self = user_data;
+  g_autoptr(IdeSourceLocation) location = NULL;
+  g_autoptr(GError) error = NULL;
   IdePerspective *editor;
   IdeWorkbench *workbench;
   IdeTree *tree;
-  GObject *item;
+
+  IDE_ENTRY;
 
   g_assert (SYMBOL_IS_TREE_BUILDER (self));
 
-  tree = ide_tree_builder_get_tree (builder);
+  location = ide_symbol_node_get_location_finish (node, result, &error);
+
+  if (location == NULL)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        g_warning ("%s", error->message);
+      IDE_EXIT;
+    }
+
+  tree = ide_tree_builder_get_tree (IDE_TREE_BUILDER (self));
   workbench = ide_widget_get_workbench (GTK_WIDGET (tree));
   editor = ide_workbench_get_perspective_by_name (workbench, "editor");
 
+  ide_editor_perspective_focus_location (IDE_EDITOR_PERSPECTIVE (editor), location);
+
+  IDE_EXIT;
+}
+
+static gboolean
+symbol_tree_builder_node_activated (IdeTreeBuilder *builder,
+                                    IdeTreeNode    *node)
+{
+  SymbolTreeBuilder *self = (SymbolTreeBuilder *)builder;
+  GObject *item;
+
+  IDE_ENTRY;
+
+  g_assert (SYMBOL_IS_TREE_BUILDER (self));
+
   item = ide_tree_node_get_item (node);
 
   if (IDE_IS_SYMBOL_NODE (item))
     {
       g_autoptr(IdeSourceLocation) location = NULL;
 
-      location = ide_symbol_node_get_location (IDE_SYMBOL_NODE (item));
+      ide_symbol_node_get_location_async (IDE_SYMBOL_NODE (item),
+                                          NULL,
+                                          symbol_tree_builder_get_location_cb,
+                                          g_object_ref (self));
 
-      if (location != NULL)
-        {
-          ide_editor_perspective_focus_location (IDE_EDITOR_PERSPECTIVE (editor), location);
-          return TRUE;
-        }
+      IDE_RETURN (TRUE);
     }
 
   g_warning ("IdeSymbolNode did not create a source location");
 
-  return FALSE;
+  IDE_RETURN (FALSE);
 }
 
 static void
diff --git a/plugins/vala-pack/ide-vala-symbol-tree.vala b/plugins/vala-pack/ide-vala-symbol-tree.vala
index 272f12f..d227b45 100644
--- a/plugins/vala-pack/ide-vala-symbol-tree.vala
+++ b/plugins/vala-pack/ide-vala-symbol-tree.vala
@@ -142,7 +142,7 @@ namespace Ide
                                this.kind = Ide.SymbolKind.FIELD;
                }
 
-               public override Ide.SourceLocation? get_location ()
+               public override async Ide.SourceLocation? get_location_async (GLib.Cancellable? cancellable)
                {
                        var source_reference = this.node.source_reference;
                        var file = (source_reference.file as Ide.ValaSourceFile).file;


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