[gnome-builder] buffers: use metadata::libide-position for cursor position



commit 9107cacb2dde34c9fd5188552d039544dde11854
Author: Christian Hergert <chergert redhat com>
Date:   Sun Jun 18 15:25:09 2017 -0700

    buffers: use metadata::libide-position for cursor position
    
    Previously, we were relying on working history to track the
    most recent cursor position. That is rather prone to failure
    so instead we'll use the gvfs backend to store
    metadata::libide-position with a value like "line:offset" to
    restore the cursor. We will also accept just "line" which will
    result in 0 being used for the offset.
    
    Line and offset use a zero index.
    
    This does require that gvfs is installed to work correctly,
    and jhbuild has been updated to include that as a dependency.
    
    Long term, we should investigate a metadata manager of sorts
    to be attached to IdeContext so that metadata operations can
    be blocked (asynchronously) during context unloading.

 libide/buffers/ide-buffer-manager.c |  124 +++++++++++++++++++---------------
 libide/files/ide-file.h             |    2 +
 2 files changed, 71 insertions(+), 55 deletions(-)
---
diff --git a/libide/buffers/ide-buffer-manager.c b/libide/buffers/ide-buffer-manager.c
index af24bb3..8a154a7 100644
--- a/libide/buffers/ide-buffer-manager.c
+++ b/libide/buffers/ide-buffer-manager.c
@@ -79,6 +79,8 @@ typedef struct
   GtkSourceFileLoader  *loader;
   guint                 is_new : 1;
   IdeWorkbenchOpenFlags flags;
+  guint                 line;
+  guint                 line_offset;
 } LoadState;
 
 typedef struct
@@ -406,6 +408,40 @@ ide_buffer_manager_track_buffer (IdeBufferManager *self,
 }
 
 static void
+ide_buffer_manager_save_cursor_position (IdeBufferManager *self,
+                                         IdeBuffer        *buffer)
+{
+  g_autofree gchar *position = NULL;
+  g_autoptr(GError) error = NULL;
+  IdeFile *file;
+  GFile *gfile;
+  GtkTextIter iter;
+
+  g_assert (IDE_IS_BUFFER_MANAGER (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  /* FIXME: We should have a metadata manager like gedit which is owned by the
+   *        context. That would allow us to do this asynchronously and block
+   *        on synchronization during unload.
+   */
+
+  file = ide_buffer_get_file (buffer);
+  if (ide_file_get_is_temporary (file))
+    return;
+
+  gfile = ide_file_get_file (file);
+
+  gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (buffer), &iter,
+                                    gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer)));
+  position = g_strdup_printf ("%u:%u",
+                              gtk_text_iter_get_line (&iter),
+                              gtk_text_iter_get_line_offset (&iter));
+
+  if (!g_file_set_attribute_string (gfile, IDE_FILE_ATTRIBUTE_POSITION, position, 0, NULL, &error))
+    g_warning ("Failed to persist cursor position: %s", error->message);
+}
+
+static void
 ide_buffer_manager_remove_buffer (IdeBufferManager *self,
                                   IdeBuffer        *buffer)
 {
@@ -433,6 +469,9 @@ ide_buffer_manager_remove_buffer (IdeBufferManager *self,
       IDE_EXIT;
     }
 
+  /* Stash the cursor position for next time we open the file */
+  ide_buffer_manager_save_cursor_position (self, buffer);
+
   /* Stealing ownership from self->buffers */
   g_ptr_array_remove_index (self->buffers, position);
 
@@ -502,17 +541,16 @@ ide_buffer_manager_load_file__load_cb (GObject      *object,
   g_autofree gchar *guess_contents = NULL;
   g_autofree gchar *content_type = NULL;
   GtkSourceFileLoader *loader = (GtkSourceFileLoader *)object;
-  IdeBackForwardList *back_forward_list;
-  IdeBackForwardItem *item;
   IdeBufferManager *self;
   const gchar *path;
   IdeContext *context;
   LoadState *state;
   GtkTextIter iter;
   GtkTextIter end;
-  GError *error = NULL;
+  g_autoptr(GError) error = NULL;
   gboolean uncertain = TRUE;
-  gsize i;
+
+  IDE_ENTRY;
 
   g_assert (G_IS_TASK (task));
   g_assert (GTK_SOURCE_IS_FILE_LOADER (loader));
@@ -547,64 +585,26 @@ ide_buffer_manager_load_file__load_cb (GObject      *object,
        */
       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
         {
-          g_task_return_error (task, error);
-          return;
+          g_task_return_error (task, g_steal_pointer (&error));
+          IDE_EXIT;
         }
-
-      g_clear_error (&error);
     }
 
   gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (state->buffer), FALSE);
 
-  for (i = 0; i < self->buffers->len; i++)
-    {
-      IdeBuffer *cur_buffer;
-
-      cur_buffer = g_ptr_array_index (self->buffers, i);
-
-      if (cur_buffer == state->buffer)
-        goto emit_signal;
-    }
-
   if (state->is_new)
     ide_buffer_manager_track_buffer (self, state->buffer);
 
-  /*
-   * If we have a navigation item for this buffer, restore the insert mark to
-   * the most recent navigation point.
-   */
-  back_forward_list = ide_context_get_back_forward_list (context);
-  item = _ide_back_forward_list_find (back_forward_list, state->file);
-
-  gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (state->buffer), &iter);
-
-  if (item != NULL && g_settings_get_boolean (self->settings, "restore-insert-mark"))
-    {
-      const gchar *fragment;
-      IdeUri *uri;
-
-      uri = ide_back_forward_item_get_uri (item);
-      fragment = ide_uri_get_fragment (uri);
-
-      if (fragment != NULL)
-        {
-          guint line = 0;
-          guint line_offset = 0;
-
-          if (sscanf (fragment, "L%u_%u", &line, &line_offset) >= 1)
-            {
-              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);
-            }
-        }
-    }
+  /* try to restore the insertion cursor */
+  if (g_settings_get_boolean (self->settings, "restore-insert-mark"))
+    gtk_text_buffer_get_iter_at_line_offset (GTK_TEXT_BUFFER (state->buffer), &iter,
+                                             state->line, state->line_offset);
   else
-    {
-      IDE_TRACE_MSG ("Restoring insert mark to 0:0");
-      gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (state->buffer), &iter);
-    }
+    gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (state->buffer), &iter);
 
+  IDE_TRACE_MSG ("Restoring insert mark to %u:%u",
+                 gtk_text_iter_get_line (&iter) + 1,
+                 gtk_text_iter_get_line_offset (&iter) + 1);
   gtk_text_buffer_select_range (GTK_TEXT_BUFFER (state->buffer), &iter, &iter);
 
   /*
@@ -621,14 +621,14 @@ ide_buffer_manager_load_file__load_cb (GObject      *object,
   if (content_type && !uncertain)
     _ide_file_set_content_type (state->file, content_type);
 
-emit_signal:
-
   if (!_ide_context_is_restoring (context))
     ide_buffer_manager_set_focus_buffer (self, state->buffer);
 
   g_signal_emit (self, signals [BUFFER_LOADED], 0, state->buffer);
 
   g_task_return_pointer (task, g_object_ref (state->buffer), g_object_unref);
+
+  IDE_EXIT;
 }
 
 static void
@@ -698,6 +698,19 @@ ide_buffer_manager__load_file_query_info_cb (GObject      *object,
       _ide_buffer_set_mtime (state->buffer, &tv);
     }
 
+  if (file_info && g_file_info_has_attribute (file_info, IDE_FILE_ATTRIBUTE_POSITION))
+    {
+      const gchar *attr = g_file_info_get_attribute_string (file_info, IDE_FILE_ATTRIBUTE_POSITION);
+      guint line = 0;
+      guint line_offset = 0;
+
+      if (attr != NULL && sscanf (attr, "%u:%u", &line, &line_offset) >= 1)
+        {
+          state->line = line;
+          state->line_offset = line_offset;
+        }
+    }
+
   create_new_view = (state->flags & IDE_WORKBENCH_OPEN_FLAGS_BACKGROUND) ? FALSE : state->is_new;
   g_signal_emit (self, signals [LOAD_BUFFER], 0, state->buffer, create_new_view);
 
@@ -748,7 +761,8 @@ ide_buffer_manager__load_file_read_cb (GObject      *object,
   g_file_query_info_async (file,
                            G_FILE_ATTRIBUTE_STANDARD_SIZE","
                            G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE","
-                           G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                           G_FILE_ATTRIBUTE_TIME_MODIFIED","
+                           IDE_FILE_ATTRIBUTE_POSITION,
                            G_FILE_QUERY_INFO_NONE,
                            G_PRIORITY_DEFAULT,
                            g_task_get_cancellable (task),
diff --git a/libide/files/ide-file.h b/libide/files/ide-file.h
index 3260cc6..cd9736a 100644
--- a/libide/files/ide-file.h
+++ b/libide/files/ide-file.h
@@ -27,6 +27,8 @@ G_BEGIN_DECLS
 
 #define IDE_TYPE_FILE (ide_file_get_type())
 
+#define IDE_FILE_ATTRIBUTE_POSITION "metadata::libide-position"
+
 G_DECLARE_FINAL_TYPE (IdeFile, ide_file, IDE, FILE, IdeObject)
 
 IdeFile           *ide_file_new                  (IdeContext           *context,


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