[gnome-builder] libide: migrate IdeBackForwardItem to use IdeUri



commit ac1b5583ea627082acf4fddf1c454de6761cab01
Author: Christian Hergert <chergert redhat com>
Date:   Sun Nov 15 21:02:12 2015 -0800

    libide: migrate IdeBackForwardItem to use IdeUri
    
    Previously we used IdeSourceLocation which made it basically impossible
    to use the navigation list for anything but source code. We really want
    to be able to navigate back/forward from anything in the view.

 libide/Makefile.am                     |    3 +
 libide/ide-back-forward-item.c         |  106 +++++++-----
 libide/ide-back-forward-item.h         |   11 +-
 libide/ide-back-forward-list-load.c    |  154 ++++++++++++++++
 libide/ide-back-forward-list-private.h |   52 ++++++
 libide/ide-back-forward-list-save.c    |  137 ++++++++++++++
 libide/ide-back-forward-list.c         |  307 ++------------------------------
 libide/ide-buffer-manager.c            |   31 +++-
 libide/ide-context.c                   |    1 +
 libide/ide-internal.h                  |   18 --
 libide/ide-source-view.c               |   19 ++-
 11 files changed, 460 insertions(+), 379 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index f92b7f0..c8774d1 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -26,6 +26,8 @@ libide_1_0_la_public_sources = \
        ide-back-forward-item.c \
        ide-back-forward-item.h \
        ide-back-forward-list.c \
+       ide-back-forward-list-load.c \
+       ide-back-forward-list-save.c \
        ide-back-forward-list.h \
        ide-buffer-change-monitor.c \
        ide-buffer-change-monitor.h \
@@ -242,6 +244,7 @@ libide_1_0_la_SOURCES = \
        ide-application-private.h \
        ide-async-helper.c \
        ide-async-helper.h \
+       ide-back-forward-list-private.h \
        ide-battery-monitor.c \
        ide-battery-monitor.h \
        ide-css-provider.c \
diff --git a/libide/ide-back-forward-item.c b/libide/ide-back-forward-item.c
index 74beb98..fb29438 100644
--- a/libide/ide-back-forward-item.c
+++ b/libide/ide-back-forward-item.c
@@ -26,49 +26,50 @@
 
 struct _IdeBackForwardItem
 {
-  IdeObject          parent_instance;
-  IdeSourceLocation *location;
+  IdeObject  parent_instance;
+  IdeUri    *uri;
 };
 
 G_DEFINE_TYPE (IdeBackForwardItem, ide_back_forward_item, IDE_TYPE_OBJECT)
 
 enum {
   PROP_0,
-  PROP_LOCATION,
+  PROP_URI,
   LAST_PROP
 };
 
 static GParamSpec *properties [LAST_PROP];
 
 IdeBackForwardItem *
-ide_back_forward_item_new (IdeContext        *context,
-                           IdeSourceLocation *location)
+ide_back_forward_item_new (IdeContext *context,
+                           IdeUri     *uri)
 {
   return g_object_new (IDE_TYPE_BACK_FORWARD_ITEM,
                        "context", context,
-                       "location", location,
+                       "uri", uri,
                        NULL);
 }
 
-IdeSourceLocation *
-ide_back_forward_item_get_location (IdeBackForwardItem *self)
+IdeUri *
+ide_back_forward_item_get_uri (IdeBackForwardItem *self)
 {
   g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (self), NULL);
 
-  return self->location;
+  return self->uri;
 }
 
 static void
-ide_back_forward_item_set_location (IdeBackForwardItem *self,
-                                    IdeSourceLocation  *location)
+ide_back_forward_item_set_uri (IdeBackForwardItem *self,
+                               IdeUri             *uri)
 {
   g_return_if_fail (IDE_IS_BACK_FORWARD_ITEM (self));
-  g_return_if_fail (location);
+  g_return_if_fail (uri != NULL);
 
-  if (location != self->location)
+  if (uri != self->uri)
     {
-      g_clear_pointer (&self->location, ide_source_location_unref);
-      self->location = ide_source_location_ref (location);
+      g_clear_pointer (&self->uri, ide_uri_unref);
+      self->uri = ide_uri_ref (uri);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_URI]);
     }
 }
 
@@ -77,7 +78,7 @@ ide_back_forward_item_finalize (GObject *object)
 {
   IdeBackForwardItem *self = (IdeBackForwardItem *)object;
 
-  g_clear_pointer (&self->location, ide_source_location_unref);
+  g_clear_pointer (&self->uri, ide_uri_unref);
 
   G_OBJECT_CLASS (ide_back_forward_item_parent_class)->finalize (object);
 }
@@ -92,8 +93,8 @@ ide_back_forward_item_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_LOCATION:
-      g_value_set_boxed (value, ide_back_forward_item_get_location (self));
+    case PROP_URI:
+      g_value_set_boxed (value, ide_back_forward_item_get_uri (self));
       break;
 
     default:
@@ -111,8 +112,8 @@ ide_back_forward_item_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_LOCATION:
-      ide_back_forward_item_set_location (self, g_value_get_boxed (value));
+    case PROP_URI:
+      ide_back_forward_item_set_uri (self, g_value_get_boxed (value));
       break;
 
     default:
@@ -130,16 +131,21 @@ ide_back_forward_item_class_init (IdeBackForwardItemClass *klass)
   object_class->set_property = ide_back_forward_item_set_property;
 
   /**
-   * IdeBackForwardItem:location:
+   * IdeBackForwardItem:uri:
    *
-   * The #IdeBackForwardItem:location property contains the location within
-   * a source file to navigate to.
+   * The #IdeBackForwardItem:uri property contains the location for the
+   * back/forward item.
+   *
+   * This might be a uri to a file, including a line number.
+   *
+   * #IdeWorkbenchAddin can hook how these are loaded, by implementing the
+   * IdeWorkbenchAddin::can_open() vfunc and associated functions.
    */
-  properties [PROP_LOCATION] =
-    g_param_spec_boxed ("location",
-                        "Location",
+  properties [PROP_URI] =
+    g_param_spec_boxed ("uri",
+                        "Uri",
                         "The location of the navigation item.",
-                        IDE_TYPE_SOURCE_LOCATION,
+                        IDE_TYPE_URI,
                         (G_PARAM_READWRITE |
                          G_PARAM_CONSTRUCT_ONLY |
                          G_PARAM_STATIC_STRINGS));
@@ -156,33 +162,43 @@ gboolean
 ide_back_forward_item_chain (IdeBackForwardItem *self,
                              IdeBackForwardItem *other)
 {
-  IdeSourceLocation *loc1;
-  IdeSourceLocation *loc2;
-  IdeFile *file1;
-  IdeFile *file2;
-  gint line1;
-  gint line2;
+  const gchar *tmp1;
+  const gchar *tmp2;
+  gint line1 = 0;
+  gint line2 = 0;
 
   g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (self), FALSE);
   g_return_val_if_fail (IDE_IS_BACK_FORWARD_ITEM (other), FALSE);
 
-  loc1 = ide_back_forward_item_get_location (self);
-  loc2 = ide_back_forward_item_get_location (other);
+  tmp1 = ide_uri_get_scheme (self->uri);
+  tmp2 = ide_uri_get_scheme (other->uri);
+  if (!ide_str_equal0 (tmp1, tmp2))
+    return FALSE;
 
-  file1 = ide_source_location_get_file (loc1);
-  file2 = ide_source_location_get_file (loc2);
+  tmp1 = ide_uri_get_host (self->uri);
+  tmp2 = ide_uri_get_host (other->uri);
+  if (!ide_str_equal0 (tmp1, tmp2))
+    return FALSE;
 
-  if (!ide_file_equal (file1, file2))
+  tmp1 = ide_uri_get_path (self->uri);
+  tmp2 = ide_uri_get_path (other->uri);
+  if (!ide_str_equal0 (tmp1, tmp2))
     return FALSE;
 
-  line1 = ide_source_location_get_line (loc1);
-  line2 = ide_source_location_get_line (loc2);
+  tmp1 = ide_uri_get_fragment (self->uri);
+  tmp2 = ide_uri_get_fragment (other->uri);
+  if ((tmp1 == NULL) || (tmp2 == NULL))
+    return FALSE;
 
-  if (ABS (line1 - line2) <= NUM_LINES_CHAIN_MAX)
-    {
-      ide_back_forward_item_set_location (self, other->location);
-      return TRUE;
-    }
+  if ((1 != sscanf (tmp1, "L%u_", &line1)) ||
+      (1 != sscanf (tmp2, "L%u_", &line2)))
+    return FALSE;
+
+  if (line1 >= G_MAXINT || line2 >= G_MAXINT)
+    return FALSE;
+
+  if (ABS (line1 - line2) < 10)
+    return TRUE;
 
   return FALSE;
 }
diff --git a/libide/ide-back-forward-item.h b/libide/ide-back-forward-item.h
index e635f5a..4837fe3 100644
--- a/libide/ide-back-forward-item.h
+++ b/libide/ide-back-forward-item.h
@@ -20,6 +20,7 @@
 #define IDE_BACK_FORWARD_ITEM_H
 
 #include "ide-object.h"
+#include "ide-uri.h"
 
 G_BEGIN_DECLS
 
@@ -27,11 +28,11 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeBackForwardItem, ide_back_forward_item, IDE, BACK_FORWARD_ITEM, IdeObject)
 
-IdeBackForwardItem *ide_back_forward_item_new          (IdeContext         *context,
-                                                        IdeSourceLocation  *location);
-IdeSourceLocation  *ide_back_forward_item_get_location (IdeBackForwardItem *self);
-gboolean            ide_back_forward_item_chain        (IdeBackForwardItem *self,
-                                                        IdeBackForwardItem *other);
+IdeBackForwardItem *ide_back_forward_item_new     (IdeContext         *context,
+                                                   IdeUri             *uri);
+IdeUri             *ide_back_forward_item_get_uri (IdeBackForwardItem *self);
+gboolean            ide_back_forward_item_chain   (IdeBackForwardItem *self,
+                                                   IdeBackForwardItem *other);
 
 G_END_DECLS
 
diff --git a/libide/ide-back-forward-list-load.c b/libide/ide-back-forward-list-load.c
new file mode 100644
index 0000000..7249f97
--- /dev/null
+++ b/libide/ide-back-forward-list-load.c
@@ -0,0 +1,154 @@
+/* ide-back-forward-list-load.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ide-back-forward-item.h"
+#include "ide-back-forward-list.h"
+#include "ide-back-forward-list-private.h"
+#include "ide-context.h"
+#include "ide-debug.h"
+
+static void
+ide_back_forward_list_load_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
+{
+  g_autoptr(GTask) task = user_data;
+  g_autofree gchar *contents = NULL;
+  g_auto(GStrv) lines = NULL;
+  IdeBackForwardList *self;
+  IdeContext *context;
+  GError *error = NULL;
+  GFile *file = (GFile *)object;
+  gsize length = 0;
+  gsize n_lines;
+  gint i;
+
+  g_assert (G_IS_FILE (file));
+  g_assert (G_IS_TASK (task));
+
+  self = g_task_get_source_object (task);
+  g_assert (IDE_IS_BACK_FORWARD_LIST (self));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  g_assert (IDE_IS_CONTEXT (context));
+
+  if (!g_file_load_contents_finish (file, result, &contents, &length, NULL, &error))
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  if (length > (10 * 1024 * 1024))
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_DATA,
+                               "Implausible file size discovered");
+      return;
+    }
+
+  if (!g_utf8_validate (contents, length, NULL))
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_INVALID_DATA,
+                               "The content was not UTF-8 formatted");
+      return;
+    }
+
+  lines = g_strsplit (contents, "\n", 0);
+  n_lines = g_strv_length (lines);
+
+  for (i = n_lines; i > 0; i--)
+    {
+      const gchar *line = lines [i - 1];
+      g_autoptr(IdeUri) uri = NULL;
+      g_autoptr(IdeBackForwardItem) item = NULL;
+      g_autofree gchar *new_style_uri = NULL;
+      char *old_style_uri = NULL;
+      guint lineno = 0;
+      guint line_offset = 0;
+
+      if (ide_str_empty0 (line))
+        continue;
+
+      /* Convert from old style "LINE OFFSET URI" to new-style "URI". */
+      if (3 == sscanf (line, "%u %u %ms", &lineno, &line_offset, &old_style_uri))
+        {
+          line = new_style_uri = g_strdup_printf ("%s#L%u_%u", old_style_uri, lineno, line_offset);
+          free (old_style_uri);
+        }
+
+      uri = ide_uri_new (line, 0, &error);
+
+      if (uri == NULL)
+        {
+          g_task_return_error (task, error);
+          return;
+        }
+
+      item = ide_back_forward_item_new (context, uri);
+      ide_back_forward_list_push (self, item);
+    }
+
+  g_task_return_boolean (task, TRUE);
+}
+
+void
+_ide_back_forward_list_load_async (IdeBackForwardList  *self,
+                                   GFile               *file,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+
+  g_assert (IDE_IS_BACK_FORWARD_LIST (self));
+  g_assert (G_IS_FILE (file));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+#ifdef IDE_ENABLE_TRACE
+  {
+    g_autofree gchar *path = NULL;
+
+    path = g_file_get_path (file);
+    IDE_TRACE_MSG ("Loading %s", path);
+  }
+#endif
+
+  task = g_task_new (self, cancellable, callback, user_data);
+
+  g_file_load_contents_async (file,
+                              cancellable,
+                              ide_back_forward_list_load_cb,
+                              g_object_ref (task));
+}
+
+gboolean
+_ide_back_forward_list_load_finish (IdeBackForwardList  *self,
+                                    GAsyncResult        *result,
+                                    GError             **error)
+{
+  g_return_val_if_fail (IDE_IS_BACK_FORWARD_LIST (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/libide/ide-back-forward-list-private.h b/libide/ide-back-forward-list-private.h
new file mode 100644
index 0000000..0031b89
--- /dev/null
+++ b/libide/ide-back-forward-list-private.h
@@ -0,0 +1,52 @@
+/* ide-back-forward-list-private.h
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#ifndef IDE_BACK_FORWARD_LIST_PRIVATE_H
+#define IDE_BACK_FORWARD_LIST_PRIVATE_H
+
+#include <gio/gio.h>
+
+#include "ide-back-forward-list.h"
+
+G_BEGIN_DECLS
+
+void                _ide_back_forward_list_foreach     (IdeBackForwardList    *self,
+                                                        GFunc                  callback,
+                                                        gpointer               user_data);
+void                _ide_back_forward_list_load_async  (IdeBackForwardList    *self,
+                                                        GFile                 *file,
+                                                        GCancellable          *cancellable,
+                                                        GAsyncReadyCallback    callback,
+                                                        gpointer               user_data);
+gboolean            _ide_back_forward_list_load_finish (IdeBackForwardList    *self,
+                                                        GAsyncResult          *result,
+                                                        GError               **error);
+void                _ide_back_forward_list_save_async  (IdeBackForwardList    *self,
+                                                        GFile                 *file,
+                                                        GCancellable          *cancellable,
+                                                        GAsyncReadyCallback    callback,
+                                                        gpointer               user_data);
+gboolean            _ide_back_forward_list_save_finish (IdeBackForwardList    *self,
+                                                        GAsyncResult          *result,
+                                                        GError               **error);
+IdeBackForwardItem *_ide_back_forward_list_find        (IdeBackForwardList    *self,
+                                                        IdeFile               *file);
+
+G_END_DECLS
+
+#endif /* IDE_BACK_FORWARD_LIST_PRIVATE_H */
diff --git a/libide/ide-back-forward-list-save.c b/libide/ide-back-forward-list-save.c
new file mode 100644
index 0000000..476abe0
--- /dev/null
+++ b/libide/ide-back-forward-list-save.c
@@ -0,0 +1,137 @@
+/* ide-back-forward-list-save.c
+ *
+ * Copyright (C) 2015 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/>.
+ */
+
+#include "ide-back-forward-item.h"
+#include "ide-back-forward-list.h"
+#include "ide-back-forward-list-private.h"
+#include "ide-debug.h"
+
+#define MAX_ITEMS_PER_FILE 5
+
+typedef struct
+{
+  GHashTable *counter;
+  GString    *content;
+} IdeBackForwardListSave;
+
+static void
+ide_back_forward_list_save_collect (gpointer data,
+                                    gpointer user_data)
+{
+  IdeBackForwardListSave *state = user_data;
+  IdeBackForwardItem *item = data;
+  g_autofree gchar *hash_key = NULL;
+  g_autofree gchar *str = NULL;
+  IdeUri *uri;
+  gsize count;
+
+  g_assert (IDE_IS_BACK_FORWARD_ITEM (item));
+  g_assert (state != NULL);
+  g_assert (state->content != NULL);
+  g_assert (state->counter != NULL);
+
+  uri = ide_back_forward_item_get_uri (item);
+
+  hash_key = g_strdup_printf ("%s://%s%s",
+                              ide_uri_get_scheme (uri) ?: "",
+                              ide_uri_get_host (uri) ?: "",
+                              ide_uri_get_path (uri) ?: "");
+
+  count = GPOINTER_TO_SIZE (g_hash_table_lookup (state->counter, hash_key));
+
+  if (count == MAX_ITEMS_PER_FILE)
+    {
+      g_free (hash_key);
+      return;
+    }
+
+  g_hash_table_insert (state->counter, hash_key, GSIZE_TO_POINTER (count + 1));
+
+  str = ide_uri_to_string (uri, 0);
+  g_string_append_printf (state->content, "%s\n", str);
+}
+
+static void
+ide_back_forward_list_save_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
+{
+  g_autoptr(GTask) task = user_data;
+  GFile *file = (GFile *)object;
+  GError *error = NULL;
+
+  g_assert (G_IS_FILE (file));
+  g_assert (G_IS_TASK (task));
+
+  if (!g_file_replace_contents_finish (file, result, NULL, &error))
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+void
+_ide_back_forward_list_save_async (IdeBackForwardList  *self,
+                                   GFile               *file,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+  GString *content;
+  GBytes *bytes;
+
+  g_return_if_fail (IDE_IS_BACK_FORWARD_LIST (self));
+  g_return_if_fail (G_IS_FILE (file));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+#ifdef IDE_ENABLE_TRACE
+  {
+    g_autofree gchar *path = NULL;
+
+    path = g_file_get_path (file);
+    IDE_TRACE_MSG ("Saving %s", path);
+  }
+#endif
+
+  task = g_task_new (self, cancellable, callback, user_data);
+
+  content = g_string_new (NULL);
+  _ide_back_forward_list_foreach (self, ide_back_forward_list_save_collect, content);
+  bytes = g_bytes_new_take (content->str, content->len + 1);
+  g_string_free (content, FALSE);
+
+  g_file_replace_contents_bytes_async (file,
+                                       bytes,
+                                       NULL,
+                                       FALSE,
+                                       G_FILE_CREATE_NONE,
+                                       cancellable,
+                                       ide_back_forward_list_save_cb,
+                                       g_object_ref (task));
+}
+
+gboolean
+_ide_back_forward_list_save_finish (IdeBackForwardList  *self,
+                                    GAsyncResult        *result,
+                                    GError             **error)
+{
+  g_return_val_if_fail (IDE_IS_BACK_FORWARD_LIST (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/libide/ide-back-forward-list.c b/libide/ide-back-forward-list.c
index 92ab663..94bb15b 100644
--- a/libide/ide-back-forward-list.c
+++ b/libide/ide-back-forward-list.c
@@ -33,8 +33,7 @@
 #include "ide-project.h"
 #include "ide-source-location.h"
 
-#define MAX_ITEMS_PER_FILE 5
-#define MAX_ITEMS_TOTAL    100
+#define MAX_ITEMS_TOTAL 100
 
 struct _IdeBackForwardList
 {
@@ -462,7 +461,7 @@ ide_back_forward_list_init (IdeBackForwardList *self)
   self->forward = g_queue_new ();
 }
 
-static void
+void
 _ide_back_forward_list_foreach (IdeBackForwardList *self,
                                 GFunc               callback,
                                 gpointer            user_data)
@@ -487,10 +486,9 @@ find_by_file (gpointer data,
               gpointer user_data)
 {
   IdeBackForwardItem *item = data;
-  IdeSourceLocation *item_loc;
-  IdeFile *item_file;
+  IdeUri *uri;
   struct {
-    IdeFile *file;
+    GFile *file;
     IdeBackForwardItem *result;
   } *lookup = user_data;
 
@@ -501,10 +499,11 @@ find_by_file (gpointer data,
   if (lookup->result)
     return;
 
-  item_loc = ide_back_forward_item_get_location (item);
-  item_file = ide_source_location_get_file (item_loc);
+  uri = ide_back_forward_item_get_uri (item);
+  if (uri == NULL)
+    return;
 
-  if (ide_file_equal (item_file, lookup->file))
+  if (ide_uri_is_file (uri, lookup->file))
     lookup->result = item;
 }
 
@@ -526,297 +525,17 @@ _ide_back_forward_list_find (IdeBackForwardList *self,
                              IdeFile            *file)
 {
   struct {
-    IdeFile *file;
+    GFile *file;
     IdeBackForwardItem *result;
-  } lookup = { file, NULL };
+  } lookup;
 
   g_return_val_if_fail (IDE_IS_BACK_FORWARD_LIST (self), NULL);
   g_return_val_if_fail (IDE_IS_FILE (file), NULL);
 
+  lookup.file = ide_file_get_file (file);
+  lookup.result = NULL;
+
   _ide_back_forward_list_foreach (self, find_by_file, &lookup);
 
   return lookup.result;
 }
-
-static void
-add_item_string (gpointer data,
-                 gpointer user_data)
-{
-  IdeBackForwardItem *item = data;
-  IdeSourceLocation *item_loc;
-  g_autofree gchar *uri = NULL;
-  IdeFile *file;
-  GFile *gfile;
-  struct {
-    GHashTable *counts;
-    GString *str;
-    guint count;
-  } *save_state = user_data;
-  guint count;
-  guint line;
-  guint line_offset;
-
-  g_assert (IDE_IS_BACK_FORWARD_ITEM (item));
-  g_assert (save_state);
-  g_assert (save_state->str);
-  g_assert (save_state->counts);
-
-  item_loc = ide_back_forward_item_get_location (item);
-  file = ide_source_location_get_file (item_loc);
-
-  count = GPOINTER_TO_INT (g_hash_table_lookup (save_state->counts, file));
-  if (count >= MAX_ITEMS_PER_FILE)
-    return;
-
-  if (save_state->count == MAX_ITEMS_TOTAL)
-    return;
-
-  save_state->count++;
-
-  g_hash_table_replace (save_state->counts, file, GINT_TO_POINTER (++count));
-
-  line = ide_source_location_get_line (item_loc);
-  line_offset = ide_source_location_get_line_offset (item_loc);
-
-  gfile = ide_file_get_file (file);
-  uri = g_file_get_uri (gfile);
-
-  g_string_append_printf (save_state->str, "%u %u %s\n", line, line_offset, uri);
-}
-
-static void
-ide_back_forward_list__replace_contents_cb (GObject      *object,
-                                            GAsyncResult *result,
-                                            gpointer      user_data)
-{
-  GFile *file = (GFile *)object;
-  g_autoptr(GTask) task = user_data;
-  GError *error = NULL;
-
-  g_assert (G_IS_FILE (file));
-  g_assert (G_IS_TASK (task));
-
-  if (!g_file_replace_contents_finish (file, result, NULL, &error))
-    g_task_return_error (task, error);
-  else
-    g_task_return_boolean (task, TRUE);
-}
-
-void
-_ide_back_forward_list_save_async (IdeBackForwardList  *self,
-                                   GFile               *file,
-                                   GCancellable        *cancellable,
-                                   GAsyncReadyCallback  callback,
-                                   gpointer             user_data)
-{
-  g_autoptr(GTask) task = NULL;
-  g_autoptr(GBytes) contents = NULL;
-  struct {
-    GHashTable *counts;
-    GString *str;
-    guint count;
-  } save_state = { 0 };
-  gsize len;
-
-  g_assert (IDE_IS_BACK_FORWARD_LIST (self));
-  g_assert (G_IS_FILE (file));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-#ifdef IDE_ENABLE_TRACE
-  {
-    g_autofree gchar *path = NULL;
-
-    path = g_file_get_path (file);
-    IDE_TRACE_MSG ("Saving %s", path);
-  }
-#endif
-
-  task = g_task_new (self, cancellable, callback, user_data);
-
-  save_state.counts = g_hash_table_new ((GHashFunc)ide_file_hash,
-                                        (GEqualFunc)ide_file_equal);
-  save_state.str = g_string_new (NULL);
-  _ide_back_forward_list_foreach (self, add_item_string, &save_state);
-  len = save_state.str->len;
-  contents = g_bytes_new_take (g_string_free (save_state.str, FALSE), len);
-  g_hash_table_destroy (save_state.counts);
-
-  g_file_replace_contents_bytes_async (file, contents, NULL, FALSE,
-                                       G_FILE_CREATE_REPLACE_DESTINATION,
-                                       cancellable,
-                                       ide_back_forward_list__replace_contents_cb,
-                                       g_object_ref (task));
-}
-
-gboolean
-_ide_back_forward_list_save_finish (IdeBackForwardList  *self,
-                                    GAsyncResult        *result,
-                                    GError             **error)
-{
-  GTask *task = (GTask *)result;
-
-  g_return_val_if_fail (IDE_IS_BACK_FORWARD_LIST (self), FALSE);
-  g_return_val_if_fail (G_IS_TASK (task), FALSE);
-
-  return g_task_propagate_boolean (task, error);
-}
-
-static IdeSourceLocation *
-create_source_location (IdeBackForwardList *self,
-                        GFile              *gfile,
-                        guint               line,
-                        guint               line_offset)
-{
-  IdeContext *context;
-  IdeProject *project;
-  g_autoptr(IdeFile) file = NULL;
-  IdeSourceLocation *ret;
-
-  g_assert (IDE_IS_BACK_FORWARD_LIST (self));
-  g_assert (G_IS_FILE (gfile));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  project = ide_context_get_project (context);
-  file = ide_project_get_project_file (project, gfile);
-
-  ret = ide_source_location_new (file, line, line_offset, 0);
-
-  return ret;
-}
-
-static void
-ide_back_forward_list__load_contents_cb (GObject      *object,
-                                         GAsyncResult *result,
-                                         gpointer      user_data)
-{
-  GFile *file = (GFile *)object;
-  IdeBackForwardList *self;
-  g_autoptr(GTask) task = user_data;
-  g_autofree gchar *contents = NULL;
-  IdeContext *context;
-  GError *error = NULL;
-  gsize length = 0;
-  gchar **lines = NULL;
-  gssize line_count;
-  gssize i;
-
-  IDE_ENTRY;
-
-  g_assert (G_IS_FILE (file));
-  g_assert (G_IS_TASK (task));
-
-  self = g_task_get_source_object (task);
-  context = ide_object_get_context (IDE_OBJECT (self));
-
-  if (!g_file_load_contents_finish (file, result, &contents, &length, NULL, &error))
-    {
-      g_task_return_error (task, error);
-      IDE_EXIT;
-    }
-
-  if (!g_utf8_validate (contents, length, NULL))
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_INVALID_DATA,
-                               _("File contained invalid UTF-8"));
-      IDE_EXIT;
-    }
-
-  lines = g_strsplit (contents, "\n", 0);
-  line_count = g_strv_length (lines);
-
-  for (i = line_count - 1; i >= 0; i--)
-    {
-      gchar **parts;
-
-      g_strstrip (lines [i]);
-
-      if (!lines [i][0])
-        continue;
-
-      parts = g_strsplit (lines [i], " ", 3);
-
-      if (g_strv_length (parts) == 3)
-        {
-          if (g_str_is_ascii (parts [0]) && g_str_is_ascii (parts [1]))
-            {
-              gint64 line;
-              gint64 line_offset;
-
-              line = g_ascii_strtoll (parts [0], NULL, 10);
-              line_offset = g_ascii_strtoll (parts [1], NULL, 10);
-
-              /*
-               * g_ascii_strtoll() will return G_MAXINT64/G_MININT64 and set errno to ERANGE. We
-               * don't really care about anything other than it being out of range.
-               */
-              if ((line >= 0) && (line <= G_MAXUINT) &&
-                  (line_offset >= 0) && (line_offset <= G_MAXUINT))
-                {
-                  g_autoptr(IdeSourceLocation) srcloc = NULL;
-                  g_autoptr(IdeBackForwardItem) item = NULL;
-                  g_autoptr(GFile) jump_file = NULL;
-
-                  jump_file = g_file_new_for_uri (parts [2]);
-                  srcloc = create_source_location (self, jump_file, line, line_offset);
-                  item = ide_back_forward_item_new (context, srcloc);
-
-                  ide_back_forward_list_push (self, item);
-                }
-            }
-        }
-
-      g_strfreev (parts);
-    }
-
-  g_strfreev (lines);
-
-  g_task_return_boolean (task, TRUE);
-
-  IDE_EXIT;
-}
-
-
-void
-_ide_back_forward_list_load_async (IdeBackForwardList  *self,
-                                   GFile               *file,
-                                   GCancellable        *cancellable,
-                                   GAsyncReadyCallback  callback,
-                                   gpointer             user_data)
-{
-  g_autoptr(GTask) task = NULL;
-
-  g_assert (IDE_IS_BACK_FORWARD_LIST (self));
-  g_assert (G_IS_FILE (file));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-#ifdef IDE_ENABLE_TRACE
-  {
-    g_autofree gchar *path = NULL;
-
-    path = g_file_get_path (file);
-    IDE_TRACE_MSG ("Loading %s", path);
-  }
-#endif
-
-  task = g_task_new (self, cancellable, callback, user_data);
-
-  g_file_load_contents_async (file,
-                              cancellable,
-                              ide_back_forward_list__load_contents_cb,
-                              g_object_ref (task));
-}
-
-gboolean
-_ide_back_forward_list_load_finish (IdeBackForwardList  *self,
-                                    GAsyncResult        *result,
-                                    GError             **error)
-{
-  GTask *task = (GTask *)result;
-
-  g_return_val_if_fail (IDE_IS_BACK_FORWARD_LIST (self), FALSE);
-  g_return_val_if_fail (G_IS_TASK (task), FALSE);
-
-  return g_task_propagate_boolean (task, error);
-}
diff --git a/libide/ide-buffer-manager.c b/libide/ide-buffer-manager.c
index 3df9e1d..8ff7de2 100644
--- a/libide/ide-buffer-manager.c
+++ b/libide/ide-buffer-manager.c
@@ -25,6 +25,7 @@
 
 #include "ide-back-forward-item.h"
 #include "ide-back-forward-list.h"
+#include "ide-back-forward-list-private.h"
 #include "ide-buffer.h"
 #include "ide-buffer-manager.h"
 #include "ide-context.h"
@@ -50,6 +51,7 @@ struct _IdeBufferManager
   GHashTable               *timeouts;
   IdeBuffer                *focus_buffer;
   GtkSourceCompletionWords *word_completion;
+  GSettings                *settings;
 
   gsize                     max_file_size;
 
@@ -505,19 +507,28 @@ ide_buffer_manager_load_file__load_cb (GObject      *object,
   back_forward_list = ide_context_get_back_forward_list (context);
   item = _ide_back_forward_list_find (back_forward_list, state->file);
 
-  if (item != NULL)
+  gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (state->buffer), &iter);
+
+  if (item != NULL && g_settings_get_boolean (self->settings, "restore-insert-mark"))
     {
-      IdeSourceLocation *item_loc;
-      guint line;
-      guint line_offset;
+      const gchar *fragment;
+      IdeUri *uri;
 
-      item_loc = ide_back_forward_item_get_location (item);
-      line = ide_source_location_get_line (item_loc);
-      line_offset = ide_source_location_get_line_offset (item_loc);
+      uri = ide_back_forward_item_get_uri (item);
+      fragment = ide_uri_get_fragment (uri);
 
-      IDE_TRACE_MSG ("Restoring insert mark to %u:%u", line, line_offset);
+      if (fragment != NULL)
+        {
+          guint line = 0;
+          guint line_offset = 0;
 
-      gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (state->buffer), &iter, line, line_offset);
+          if (1 == sscanf (fragment, "L%u_%u", &line, &line_offset))
+            {
+              IDE_TRACE_MSG ("Restoring insert mark to %u:%u", line, line_offset);
+              gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (state->buffer), &iter,
+                                                       line, line_offset);
+            }
+        }
     }
   else
     {
@@ -1189,6 +1200,7 @@ ide_buffer_manager_finalize (GObject *object)
 
   g_clear_pointer (&self->buffers, g_ptr_array_unref);
   g_clear_pointer (&self->timeouts, g_hash_table_unref);
+  g_clear_object (&self->settings);
 
   G_OBJECT_CLASS (ide_buffer_manager_parent_class)->finalize (object);
 }
@@ -1420,6 +1432,7 @@ ide_buffer_manager_init (IdeBufferManager *self)
   self->max_file_size = MAX_FILE_SIZE_BYTES_DEFAULT;
   self->timeouts = g_hash_table_new (g_direct_hash, g_direct_equal);
   self->word_completion = gtk_source_completion_words_new (_("Words"), NULL);
+  self->settings = g_settings_new ("org.gnome.builder.editor");
 }
 
 static void
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 6cb2fbe..1aef8b9 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -23,6 +23,7 @@
 
 #include "ide-async-helper.h"
 #include "ide-back-forward-list.h"
+#include "ide-back-forward-list-private.h"
 #include "ide-buffer-manager.h"
 #include "ide-buffer.h"
 #include "ide-build-system.h"
diff --git a/libide/ide-internal.h b/libide/ide-internal.h
index 474283f..c9c5c9b 100644
--- a/libide/ide-internal.h
+++ b/libide/ide-internal.h
@@ -33,24 +33,6 @@
 
 G_BEGIN_DECLS
 
-void                _ide_back_forward_list_load_async       (IdeBackForwardList    *self,
-                                                             GFile                 *file,
-                                                             GCancellable          *cancellable,
-                                                             GAsyncReadyCallback    callback,
-                                                             gpointer               user_data);
-gboolean            _ide_back_forward_list_load_finish      (IdeBackForwardList    *self,
-                                                             GAsyncResult          *result,
-                                                             GError               **error);
-void                _ide_back_forward_list_save_async       (IdeBackForwardList    *self,
-                                                             GFile                 *file,
-                                                             GCancellable          *cancellable,
-                                                             GAsyncReadyCallback    callback,
-                                                             gpointer               user_data);
-gboolean            _ide_back_forward_list_save_finish      (IdeBackForwardList    *self,
-                                                             GAsyncResult          *result,
-                                                             GError               **error);
-IdeBackForwardItem *_ide_back_forward_list_find             (IdeBackForwardList    *self,
-                                                             IdeFile               *file);
 void                _ide_battery_monitor_init               (void);
 void                _ide_battery_monitor_shutdown           (void);
 void                _ide_buffer_set_changed_on_volume       (IdeBuffer             *self,
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index fa59323..1aa7dae 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -2792,13 +2792,13 @@ ide_source_view_real_jump (IdeSourceView     *self,
                            const GtkTextIter *location)
 {
   IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
-  g_autoptr(IdeSourceLocation) srcloc = NULL;
-  g_autoptr(IdeBackForwardItem) item = NULL;
+  IdeBackForwardItem *item;
   IdeContext *context;
   IdeFile *file;
+  IdeUri *uri;
+  gchar *fragment;
   guint line;
   guint line_offset;
-  guint offset;
 
   IDE_ENTRY;
 
@@ -2819,15 +2819,18 @@ ide_source_view_real_jump (IdeSourceView     *self,
   if (file == NULL)
     IDE_EXIT;
 
+  uri = ide_uri_new_from_file (ide_file_get_file (file));
   line = gtk_text_iter_get_line (location);
   line_offset = gtk_text_iter_get_line_offset (location);
-  offset = gtk_text_iter_get_offset (location);
-
-  srcloc = ide_source_location_new (file, line, line_offset, offset);
-  item = ide_back_forward_item_new (context, srcloc);
-
+  fragment = g_strdup_printf ("L%u_%u", line, line_offset);
+  ide_uri_set_fragment (uri, fragment);
+  item = ide_back_forward_item_new (context, uri);
   ide_back_forward_list_push (priv->back_forward_list, item);
 
+  g_object_unref (item);
+  ide_uri_unref (uri);
+  g_free (fragment);
+
   IDE_EXIT;
 }
 



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