[gnome-builder/wip/ggit] ggit: start on playing with using libgit2-glib for diff parsing.



commit c6e35ba4df21b95013456d0aff2b18a342423d11
Author: Christian Hergert <christian hergert me>
Date:   Fri Sep 26 19:16:07 2014 -0700

    ggit: start on playing with using libgit2-glib for diff parsing.

 build/autotools/autoconf.d/50_dependencies.post-am |    1 +
 src/editor/gb-editor-commands.c                    |    2 -
 src/editor/gb-editor-tab.c                         |    3 +
 src/editor/gb-source-change-monitor.c              |  620 ++++++++------------
 src/editor/gb-source-change-monitor.h              |    5 +-
 src/gnome-builder.mk                               |    2 +
 src/main.c                                         |    2 +
 7 files changed, 246 insertions(+), 389 deletions(-)
---
diff --git a/build/autotools/autoconf.d/50_dependencies.post-am 
b/build/autotools/autoconf.d/50_dependencies.post-am
index bacadc1..a927b6b 100644
--- a/build/autotools/autoconf.d/50_dependencies.post-am
+++ b/build/autotools/autoconf.d/50_dependencies.post-am
@@ -2,3 +2,4 @@ PKG_CHECK_MODULES(GTK, gtk+-3.0 >= 3.13.9)
 PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.40.0)
 PKG_CHECK_MODULES(GTKSOURCEVIEW, gtksourceview-3.0 >= 3.13.91)
 PKG_CHECK_MODULES(DEVHELP, libdevhelp-3.0 >= 3.13.90)
+PKG_CHECK_MODULES(GGIT, libgit2-glib-1.0 >= 0.0.22)
diff --git a/src/editor/gb-editor-commands.c b/src/editor/gb-editor-commands.c
index 15df339..ebaaae5 100644
--- a/src/editor/gb-editor-commands.c
+++ b/src/editor/gb-editor-commands.c
@@ -396,7 +396,6 @@ on_load_cb (GtkSourceFileLoader *loader,
   gtk_text_buffer_select_range (GTK_TEXT_BUFFER (tab->priv->document),
                                 &begin, &begin);
 
-  gb_source_change_monitor_reset (tab->priv->change_monitor);
   gtk_source_gutter_renderer_set_visible (tab->priv->change_renderer, TRUE);
 
   g_object_unref (tab);
@@ -463,7 +462,6 @@ on_save_cb (GtkSourceFileSaver *saver,
     {
       gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (tab->priv->document),
                                     FALSE);
-      gb_source_change_monitor_saved (tab->priv->change_monitor);
       gtk_widget_queue_draw (GTK_WIDGET (tab->priv->source_view));
     }
 
diff --git a/src/editor/gb-editor-tab.c b/src/editor/gb-editor-tab.c
index 8fae8fc..0d00e04 100644
--- a/src/editor/gb-editor-tab.c
+++ b/src/editor/gb-editor-tab.c
@@ -1060,6 +1060,9 @@ gb_editor_tab_constructed (GObject *object)
                           priv->source_view, "show-shadow",
                           G_BINDING_SYNC_CREATE);
 
+  g_object_bind_property (priv->file, "location",
+                          priv->change_monitor, "file",
+                          G_BINDING_SYNC_CREATE);
   g_object_bind_property_full (priv->file, "location", tab, "title",
                                G_BINDING_SYNC_CREATE, transform_file_to_title,
                                NULL, tab, NULL);
diff --git a/src/editor/gb-source-change-monitor.c b/src/editor/gb-source-change-monitor.c
index 861b830..eb91866 100644
--- a/src/editor/gb-source-change-monitor.c
+++ b/src/editor/gb-source-change-monitor.c
@@ -19,28 +19,29 @@
 #define G_LOG_DOMAIN "change-monitor"
 
 #include <glib/gi18n.h>
+#include <gtksourceview/gtksource.h>
+#include <libgit2-glib/ggit.h>
 
 #include "gb-log.h"
 #include "gb-source-change-monitor.h"
 
+#define PARSE_TIMEOUT_MSEC 1000
+
 struct _GbSourceChangeMonitorPrivate
 {
-  GtkTextBuffer *buffer;
-  GArray        *state;
-
-  guint delete_range_before_handler;
-  guint delete_range_after_handler;
-  guint insert_text_before_handler;
-  guint insert_text_after_handler;
-
-  guint insert_begin_line;
-  guint insert_begin_offset;
+  GtkTextBuffer  *buffer;
+  GFile          *file;
+  GgitRepository *repo;
+  GHashTable     *state;
+  guint           changed_handler;
+  guint           parse_timeout;
 };
 
 enum
 {
   PROP_0,
   PROP_BUFFER,
+  PROP_FILE,
   LAST_PROP
 };
 
@@ -50,381 +51,208 @@ G_DEFINE_TYPE_WITH_PRIVATE (GbSourceChangeMonitor,
 
 static GParamSpec *gParamSpecs [LAST_PROP];
 
-
-static void
-gb_source_change_monitor_insert (GbSourceChangeMonitor *monitor,
-                                 guint                  line,
-                                 GbSourceChangeFlags    flags)
+GbSourceChangeFlags
+gb_source_change_monitor_get_line (GbSourceChangeMonitor *monitor,
+                                   guint                  lineno)
 {
-  guint8 byte = (guint8)flags;
+  g_return_val_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor), 0);
 
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
+  if (monitor->priv->state)
+    {
+      gpointer value;
+
+      value = g_hash_table_lookup (monitor->priv->state,
+                                   GINT_TO_POINTER (lineno));
+      return GPOINTER_TO_INT (value);
+    }
 
-  if (line == monitor->priv->state->len)
-    g_array_append_val (monitor->priv->state, byte);
-  else
-    g_array_insert_val (monitor->priv->state, line, byte);
+  return GB_SOURCE_CHANGE_NONE;
 }
 
-static void
-gb_source_change_monitor_remove (GbSourceChangeMonitor *monitor,
-                                 guint                  line)
+static gboolean
+on_parse_timeout (GbSourceChangeMonitor *monitor)
 {
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
-  g_return_if_fail (line < monitor->priv->state->len);
+  GbSourceChangeMonitorPrivate *priv;
+  GgitOId *entry_oid = NULL;
+  GgitOId *oid = NULL;
+  GgitObject *blob = NULL;
+  GgitObject *commit = NULL;
+  GgitRef *head = NULL;
+  GgitTree *tree = NULL;
+  GgitTreeEntry *entry = NULL;
+  GFile *workdir = NULL;
+  GError *error = NULL;
+  gchar *relpath = NULL;
 
-  g_array_remove_index (monitor->priv->state, line);
-}
+  ENTRY;
 
-static void
-gb_source_change_monitor_set_line (GbSourceChangeMonitor *monitor,
-                                   guint                  line,
-                                   GbSourceChangeFlags    flags)
-{
-  GbSourceChangeFlags old_flags;
+  g_assert (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
 
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
-  g_return_if_fail (line < monitor->priv->state->len);
+  priv = monitor->priv;
 
-  old_flags = g_array_index (monitor->priv->state, guint8, line);
+  /*
+   * First, disable this so any side-effects cause a new parse to occur.
+   */
+  priv->parse_timeout = 0;
 
   /*
-   * Don't allow ourselves to go from "added" to "changed" unless we
-   * previously did not have a dirty bit.
+   * We are about to invalidate everything, so just clear out the hash table.
    */
-  if (((old_flags & GB_SOURCE_CHANGE_ADDED) != 0) &&
-      ((old_flags & GB_SOURCE_CHANGE_DIRTY) != 0))
-    {
-      flags &= ~GB_SOURCE_CHANGE_CHANGED;
-      flags |= GB_SOURCE_CHANGE_ADDED;
-    }
+  g_hash_table_remove_all (priv->state);
 
-  g_array_index (monitor->priv->state, guint8, line) = (guint8)flags;
-}
+  /*
+   * Double check we have everything we need.
+   */
+  if (!priv->repo)
+    RETURN (G_SOURCE_REMOVE);
 
-static void
-gb_source_change_monitor_ensure_bounds (GbSourceChangeMonitor *monitor)
-{
-  GbSourceChangeMonitorPrivate *priv;
-  GtkTextIter begin;
-  GtkTextIter end;
-  guint line;
+  /*
+   * Work our way through ggit to get to the original blog we care about.
+   */
+  head = ggit_repository_get_head (priv->repo, &error);
+  if (!head)
+    GOTO (cleanup);
 
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
+  oid = ggit_ref_get_target (head);
+  if (!oid)
+    GOTO (cleanup);
 
-  priv = monitor->priv;
+  commit = ggit_repository_lookup (priv->repo, oid, GGIT_TYPE_COMMIT, &error);
+  if (!commit)
+    GOTO (cleanup);
 
-  gtk_text_buffer_get_bounds (priv->buffer, &begin, &end);
+  tree = ggit_commit_get_tree (GGIT_COMMIT (commit));
+  if (!tree)
+    GOTO (cleanup);
 
-  line = gtk_text_iter_get_line (&end);
+  workdir = ggit_repository_get_workdir (priv->repo);
+  if (!workdir)
+    GOTO (cleanup);
 
-  if (line + 1 > priv->state->len)
-    g_array_set_size (priv->state, line + 1);
-}
+  relpath = g_file_get_relative_path (workdir, priv->file);
+  if (!relpath)
+    GOTO (cleanup);
 
-static void
-get_line_mutation (const GtkTextIter *begin,
-                   const GtkTextIter *end,
-                   guint              line,
-                   gboolean          *delete_line,
-                   gboolean          *is_changed)
-{
-  guint begin_line;
-  guint begin_offset;
-  guint end_line;
-  guint end_offset;
+  entry = ggit_tree_get_by_path (tree, relpath, &error);
+  if (!entry)
+    GOTO (cleanup);
 
-  ENTRY;
+  entry_oid = ggit_tree_entry_get_id (entry);
+  if (!entry_oid)
+    GOTO (cleanup);
 
-  begin_line = gtk_text_iter_get_line (begin);
-  begin_offset = gtk_text_iter_get_line_offset (begin);
-  end_line = gtk_text_iter_get_line (end);
-  end_offset = gtk_text_iter_get_line_offset (end);
+  blob = ggit_repository_lookup (priv->repo, entry_oid, GGIT_TYPE_BLOB, &error);
+  if (!blob)
+    GOTO (cleanup);
 
-  if (begin_line == end_line)
-    {
-      *delete_line = FALSE;
-      *is_changed = TRUE;
-      EXIT;
-    }
-  else if ((line == begin_line) &&
-           gtk_text_iter_starts_line (begin) &&
-           gtk_text_iter_starts_line (end))
-    {
-      *delete_line = TRUE;
-      *is_changed = FALSE;
-      EXIT;
-    }
-  else if ((line == begin_line) &&
-           ((begin_line + 1) == end_line) &&
-           gtk_text_iter_ends_line (begin) &&
-           gtk_text_iter_starts_line (end))
-    {
-      *delete_line = FALSE;
-      *is_changed = FALSE;
-      EXIT;
-    }
-  else if ((begin_offset != 0) && (line == begin_line))
-    {
-      *delete_line = FALSE;
-      *is_changed = TRUE;
-      EXIT;
-    }
-  else if ((line == end_line) && (end_offset == 0))
-    {
-      *delete_line = FALSE;
-      *is_changed = FALSE;
-      EXIT;
-    }
-  else if ((begin_offset == 0) && (line == begin_line) && (begin_line != end_line))
-    {
-      *delete_line = TRUE;
-      *is_changed = FALSE;
-      EXIT;
-    }
-  else if ((line != begin_line) && (line != end_line))
-    {
-      *delete_line = TRUE;
-      *is_changed = FALSE;
-      EXIT;
-    }
-  else if ((line != begin_line) && (line == end_line) && (begin_offset != 0))
-    {
-      *delete_line = TRUE;
-      *is_changed = FALSE;
-      EXIT;
-    }
-  else if ((line != begin_line) && (line == end_line) && (begin_offset == 0))
+cleanup:
+  if (error)
     {
-      *delete_line = FALSE;
-      *is_changed = TRUE;
-      EXIT;
-    }
-  else
-    {
-      g_warning ("Unknown outcome: begin=%d:%d line=%d end_line=%d:%d",
-                 begin_line, begin_offset, line, end_line, end_offset);
-
-      *is_changed = TRUE;
-      *delete_line = FALSE;
-      EXIT;
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
     }
-
-  EXIT;
+  g_clear_object (&blob);
+  g_clear_object (&commit);
+  g_clear_object (&entry);
+  g_clear_object (&entry_oid);
+  g_clear_object (&head);
+  g_clear_object (&oid);
+  g_clear_object (&tree);
+  g_clear_object (&workdir);
+  g_clear_pointer (&relpath, g_free);
+
+  RETURN (G_SOURCE_REMOVE);
 }
 
 static void
-on_delete_range_before_cb (GbSourceChangeMonitor *monitor,
-                           GtkTextIter           *begin,
-                           GtkTextIter           *end,
-                           GtkTextBuffer         *buffer)
+gb_source_change_monitor_queue_parse (GbSourceChangeMonitor *monitor)
 {
-  GArray *ar;
-  guint begin_line;
-  guint end_line;
-  guint i;
+  GbSourceChangeMonitorPrivate *priv;
 
   g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
-  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
-
-  if (gtk_text_iter_compare (begin, end) == 0)
-    return;
-
-  begin_line = gtk_text_iter_get_line (begin);
-  end_line = gtk_text_iter_get_line (end);
 
-  ar = g_array_new (FALSE, FALSE, sizeof (guint));
+  priv = monitor->priv;
 
-  for (i = begin_line; i <= end_line; i++)
+  if (priv->parse_timeout)
     {
-      gboolean delete_line;
-      gboolean is_changed;
-
-      get_line_mutation (begin, end, i, &delete_line, &is_changed);
-
-      if (delete_line)
-        g_array_append_val (ar, i);
-      else if (is_changed)
-        gb_source_change_monitor_set_line (monitor, i,
-                                           (GB_SOURCE_CHANGE_CHANGED |
-                                            GB_SOURCE_CHANGE_DIRTY));
+      g_source_remove (priv->parse_timeout);
+      priv->parse_timeout = 0;
     }
 
-  for (i = ar->len; i > 0; i--)
-    {
-      guint line;
-
-      line = g_array_index (ar, guint, i - 1);
-      gb_source_change_monitor_remove (monitor, line);
-    }
-
-  g_array_unref (ar);
+  priv->parse_timeout = g_timeout_add (PARSE_TIMEOUT_MSEC,
+                                       (GSourceFunc)on_parse_timeout,
+                                       monitor);
 }
 
 static void
-on_delete_range_after_cb (GbSourceChangeMonitor *monitor,
-                          GtkTextIter           *begin,
-                          GtkTextIter           *end,
-                          GtkTextBuffer         *buffer)
+on_change_cb (GbSourceChangeMonitor *monitor,
+              GtkTextBuffer         *buffer)
 {
   g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
   g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+
+  gb_source_change_monitor_queue_parse (monitor);
 }
 
 static void
-on_insert_text_before_cb (GbSourceChangeMonitor *monitor,
-                          GtkTextIter           *location,
-                          gchar                 *text,
-                          gint                   len,
-                          GtkTextBuffer         *buffer)
+discover_repository (GbSourceChangeMonitor *monitor)
 {
   GbSourceChangeMonitorPrivate *priv;
-  GtkTextIter begin;
-  GtkTextIter end;
-
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
-  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
-
-  priv = monitor->priv;
 
-  priv->insert_begin_line = gtk_text_iter_get_line (location);
-  priv->insert_begin_offset = gtk_text_iter_get_line_offset (location);
+  ENTRY;
 
-  gtk_text_buffer_get_bounds (buffer, &begin, &end);
+  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
 
   /*
-   * WORKAROUND:
+   * TODO: This makes a lot of assumptions.
+   *   - that we are local
+   *   - that checking disk is free
+   *   - that we don't need to cache anything.
    *
-   * Mark the first line as added if we are typing our first character.
-   * We should consider removing this GSignal handler after it has
-   * hit this to save on signal emission.
+   *  and all of those are probably wrong.
    */
-  if (G_UNLIKELY (gtk_text_iter_compare (&begin, &end) == 0))
-    gb_source_change_monitor_set_line (monitor, 0,
-                                       (GB_SOURCE_CHANGE_ADDED |
-                                        GB_SOURCE_CHANGE_DIRTY));
-}
-
-static void
-on_insert_text_after_cb (GbSourceChangeMonitor *monitor,
-                         GtkTextIter           *location,
-                         gchar                 *text,
-                         gint                   len,
-                         GtkTextBuffer         *buffer)
-{
-  GbSourceChangeMonitorPrivate *priv;
-  GbSourceChangeFlags flags = 0;
-  guint line;
-
-  ENTRY;
-
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
-  g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
 
   priv = monitor->priv;
 
-  line = gtk_text_iter_get_line (location);
+  g_clear_object (&priv->repo);
 
-  if (g_strcmp0 (text, "\n") == 0)
+  if (priv->file)
     {
-      flags = (GB_SOURCE_CHANGE_ADDED | GB_SOURCE_CHANGE_DIRTY);
-      if (priv->insert_begin_offset == 0)
-        gb_source_change_monitor_insert (monitor, line-1, flags);
-      else
-        gb_source_change_monitor_insert (monitor, line, flags);
-    }
-  else if (strchr (text, '\n') == NULL)
-    {
-      flags = (GB_SOURCE_CHANGE_CHANGED | GB_SOURCE_CHANGE_DIRTY);
-      gb_source_change_monitor_set_line (monitor, line, flags);
-    }
-  else
-    {
-      GtkTextIter end;
-      GtkTextIter iter;
-      guint last_line;
-
-      len = g_utf8_strlen (text, len);
+      GFile *repo_file;
+      GError *error = NULL;
 
-      gtk_text_iter_assign (&iter, location);
-      gtk_text_iter_assign (&end, location);
-      gtk_text_iter_backward_chars (&iter, len);
+      repo_file = ggit_repository_discover (priv->file, &error);
 
-      last_line = gtk_text_iter_get_line (&iter);
+      TRACE;
 
-      while (gtk_text_iter_compare (&iter, &end) <= 0)
+      if (!repo_file)
         {
-          line = gtk_text_iter_get_line (&iter);
-
-          if (line != last_line)
-            {
-              flags = (GB_SOURCE_CHANGE_ADDED | GB_SOURCE_CHANGE_DIRTY);
-              gb_source_change_monitor_insert (monitor, line, flags);
-              last_line = line;
-            }
-
-          if (!gtk_text_iter_forward_char (&iter))
-            break;
+          g_message ("%s", error->message);
+          g_clear_error (&error);
+          EXIT;
         }
-    }
-
-  gb_source_change_monitor_ensure_bounds (monitor);
-
-  EXIT;
-}
-
-GbSourceChangeFlags
-gb_source_change_monitor_get_line (GbSourceChangeMonitor *monitor,
-                                   guint                  lineno)
-{
-  g_return_val_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor), 0);
-
-  if (lineno < monitor->priv->state->len)
-    return monitor->priv->state->data [lineno];
-
-  g_warning ("No such line: %u", lineno);
-
-  return 0;
-}
 
-void
-gb_source_change_monitor_saved (GbSourceChangeMonitor *monitor)
-{
-  GbSourceChangeMonitorPrivate *priv;
-  GbSourceChangeFlags flags;
-  guint i;
+      priv->repo = ggit_repository_open (repo_file, &error);
+      TRACE;
 
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
+      if (!priv->repo)
+        {
+          g_message ("%s", error->message);
+          g_clear_error (&error);
+        }
+      else
+        {
+          gchar *uri;
 
-  priv = monitor->priv;
+          uri = g_file_get_uri (repo_file);
+          g_message ("Discovered Git repository at \"%s\"", uri);
+          g_free (uri);
+        }
 
-  for (i = 0; i < priv->state->len; i++)
-    {
-      flags = g_array_index (priv->state, guint8, i);
-      flags &= ~GB_SOURCE_CHANGE_DIRTY;
-      g_array_index (priv->state, guint8, i) = flags;
+      g_clear_object (&repo_file);
     }
-}
-
-void
-gb_source_change_monitor_reset (GbSourceChangeMonitor *monitor)
-{
-  GbSourceChangeMonitorPrivate *priv;
-  GtkTextIter begin;
-  GtkTextIter end;
-  guint line;
 
-  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
-
-  priv = monitor->priv;
-
-  if (priv->buffer)
-    {
-      gtk_text_buffer_get_bounds (priv->buffer, &begin, &end);
-      line = gtk_text_iter_get_line (&end);
-      g_array_set_size (priv->state, line + 1);
-      memset (priv->state->data, 0, priv->state->len);
-    }
+  EXIT;
 }
 
 GtkTextBuffer *
@@ -437,8 +265,7 @@ gb_source_change_monitor_get_buffer (GbSourceChangeMonitor *monitor)
 
 static void
 gb_source_change_monitor_set_buffer (GbSourceChangeMonitor *monitor,
-                                     GtkTextBuffer         *buffer,
-                                     gboolean               notify)
+                                     GtkTextBuffer         *buffer)
 {
   GbSourceChangeMonitorPrivate *priv;
 
@@ -451,54 +278,53 @@ gb_source_change_monitor_set_buffer (GbSourceChangeMonitor *monitor,
 
   if (priv->buffer)
     {
-      g_signal_handler_disconnect (priv->buffer,
-                                   priv->delete_range_before_handler);
-      g_signal_handler_disconnect (priv->buffer,
-                                   priv->delete_range_after_handler);
-      g_signal_handler_disconnect (priv->buffer,
-                                   priv->insert_text_before_handler);
-      g_signal_handler_disconnect (priv->buffer,
-                                   priv->insert_text_after_handler);
-      priv->delete_range_before_handler = 0;
-      priv->delete_range_after_handler = 0;
-      priv->insert_text_before_handler = 0;
-      priv->insert_text_after_handler = 0;
+      g_signal_handler_disconnect (priv->buffer, priv->changed_handler);
+      priv->changed_handler = 0;
       g_clear_object (&priv->buffer);
     }
 
   if (buffer)
     {
       priv->buffer = g_object_ref (buffer);
-      priv->delete_range_before_handler =
+      priv->changed_handler =
         g_signal_connect_object (priv->buffer,
-                                 "delete-range",
-                                 G_CALLBACK (on_delete_range_before_cb),
+                                 "changed",
+                                 G_CALLBACK (on_change_cb),
                                  monitor,
                                  G_CONNECT_SWAPPED);
-      priv->delete_range_after_handler =
-        g_signal_connect_object (priv->buffer,
-                                 "delete-range",
-                                 G_CALLBACK (on_delete_range_after_cb),
-                                 monitor,
-                                 (G_CONNECT_SWAPPED | G_CONNECT_AFTER));
-      priv->insert_text_before_handler =
-        g_signal_connect_object (priv->buffer,
-                                 "insert-text",
-                                 G_CALLBACK (on_insert_text_before_cb),
-                                 monitor,
-                                 G_CONNECT_SWAPPED);
-      priv->insert_text_after_handler =
-        g_signal_connect_object (priv->buffer,
-                                 "insert-text",
-                                 G_CALLBACK (on_insert_text_after_cb),
-                                 monitor,
-                                 (G_CONNECT_SWAPPED | G_CONNECT_AFTER));
-
-      gb_source_change_monitor_ensure_bounds (monitor);
     }
 
-  if (notify)
-    g_object_notify_by_pspec (G_OBJECT (monitor), gParamSpecs [PROP_BUFFER]);
+  EXIT;
+}
+
+GFile *
+gb_source_change_monitor_get_file (GbSourceChangeMonitor *monitor)
+{
+  g_return_val_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor), NULL);
+
+  return monitor->priv->file;
+}
+
+void
+gb_source_change_monitor_set_file (GbSourceChangeMonitor *monitor,
+                                   GFile                 *file)
+{
+  GbSourceChangeMonitorPrivate *priv;
+
+  ENTRY;
+
+  g_return_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor));
+  g_return_if_fail (!file || G_IS_FILE (file));
+
+  priv = monitor->priv;
+
+  if (file == priv->file)
+    EXIT;
+
+  g_clear_object (&priv->file);
+  monitor->priv->file = file ? g_object_ref (file) : NULL;
+  discover_repository (monitor);
+  g_object_notify_by_pspec (G_OBJECT (monitor), gParamSpecs [PROP_FILE]);
 
   EXIT;
 }
@@ -506,10 +332,20 @@ gb_source_change_monitor_set_buffer (GbSourceChangeMonitor *monitor,
 static void
 gb_source_change_monitor_dispose (GObject *object)
 {
+  GbSourceChangeMonitor *monitor = (GbSourceChangeMonitor *)object;
+
   ENTRY;
 
-  gb_source_change_monitor_set_buffer (GB_SOURCE_CHANGE_MONITOR (object),
-                                       NULL, FALSE);
+  gb_source_change_monitor_set_buffer (monitor, NULL);
+  gb_source_change_monitor_set_file (monitor, NULL);
+
+  g_clear_object (&monitor->priv->repo);
+
+  if (monitor->priv->parse_timeout)
+    {
+      g_source_remove (monitor->priv->parse_timeout);
+      monitor->priv->parse_timeout = 0;
+    }
 
   G_OBJECT_CLASS (gb_source_change_monitor_parent_class)->dispose (object);
 
@@ -519,17 +355,11 @@ gb_source_change_monitor_dispose (GObject *object)
 static void
 gb_source_change_monitor_finalize (GObject *object)
 {
-  GbSourceChangeMonitorPrivate *priv;
+  GbSourceChangeMonitorPrivate *priv = GB_SOURCE_CHANGE_MONITOR (object)->priv;
 
-  ENTRY;
-
-  priv = GB_SOURCE_CHANGE_MONITOR (object)->priv;
-
-  g_clear_pointer (&priv->state, g_array_unref);
+  g_clear_pointer (&priv->state, g_hash_table_unref);
 
   G_OBJECT_CLASS (gb_source_change_monitor_parent_class)->finalize (object);
-
-  EXIT;
 }
 
 static void
@@ -540,14 +370,21 @@ gb_source_change_monitor_get_property (GObject    *object,
 {
   GbSourceChangeMonitor *monitor = GB_SOURCE_CHANGE_MONITOR (object);
 
-  switch (prop_id) {
-  case PROP_BUFFER:
-    g_value_set_object (value,
-                        gb_source_change_monitor_get_buffer (monitor));
-    break;
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-  }
+  switch (prop_id)
+    {
+    case PROP_BUFFER:
+      g_value_set_object (value,
+                          gb_source_change_monitor_get_buffer (monitor));
+      break;
+
+    case PROP_FILE:
+      g_value_set_object (value,
+                          gb_source_change_monitor_get_file (monitor));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
 }
 
 static void
@@ -558,15 +395,20 @@ gb_source_change_monitor_set_property (GObject      *object,
 {
   GbSourceChangeMonitor *monitor = GB_SOURCE_CHANGE_MONITOR (object);
 
-  switch (prop_id) {
-  case PROP_BUFFER:
-    gb_source_change_monitor_set_buffer (monitor,
-                                         g_value_get_object (value),
-                                         TRUE);
-    break;
-  default:
-    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-  }
+  switch (prop_id)
+    {
+    case PROP_BUFFER:
+      gb_source_change_monitor_set_buffer (monitor,
+                                           g_value_get_object (value));
+      break;
+
+    case PROP_FILE:
+      gb_source_change_monitor_set_file (monitor, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
 }
 
 static void
@@ -590,17 +432,23 @@ gb_source_change_monitor_class_init (GbSourceChangeMonitorClass *klass)
                           G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_BUFFER,
                                    gParamSpecs [PROP_BUFFER]);
+
+  gParamSpecs [PROP_FILE] =
+    g_param_spec_object ("file",
+                         _("File"),
+                         _("The file for the buffer."),
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE |
+                          G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_FILE,
+                                   gParamSpecs [PROP_FILE]);
 }
 
 static void
 gb_source_change_monitor_init (GbSourceChangeMonitor *monitor)
 {
   ENTRY;
-
   monitor->priv = gb_source_change_monitor_get_instance_private (monitor);
-
-  monitor->priv->state = g_array_new (FALSE, TRUE, sizeof (guint8));
-  g_array_set_size (monitor->priv->state, 1);
-
+  monitor->priv->state = g_hash_table_new (g_direct_hash, g_direct_equal);
   EXIT;
 }
diff --git a/src/editor/gb-source-change-monitor.h b/src/editor/gb-source-change-monitor.h
index 04f1ad1..56805b5 100644
--- a/src/editor/gb-source-change-monitor.h
+++ b/src/editor/gb-source-change-monitor.h
@@ -37,6 +37,7 @@ typedef struct _GbSourceChangeMonitorPrivate GbSourceChangeMonitorPrivate;
 
 typedef enum
 {
+  GB_SOURCE_CHANGE_NONE    = 0,
   GB_SOURCE_CHANGE_DIRTY   = 1 << 0,
   GB_SOURCE_CHANGE_ADDED   = 1 << 1,
   GB_SOURCE_CHANGE_CHANGED = 1 << 2,
@@ -57,9 +58,11 @@ struct _GbSourceChangeMonitorClass
 
 GType                  gb_source_change_monitor_get_type (void) G_GNUC_CONST;
 GbSourceChangeMonitor *gb_source_change_monitor_new      (GtkTextBuffer         *buffer);
+GFile                 *gb_source_change_monitor_get_file (GbSourceChangeMonitor *monitor);
+void                   gb_source_change_monitor_set_file (GbSourceChangeMonitor *monitor,
+                                                          GFile                 *file);
 GbSourceChangeFlags    gb_source_change_monitor_get_line (GbSourceChangeMonitor *monitor,
                                                           guint                  lineno);
-void                   gb_source_change_monitor_reset    (GbSourceChangeMonitor *monitor);
 void                   gb_source_change_monitor_saved    (GbSourceChangeMonitor *monitor);
 
 G_END_DECLS
diff --git a/src/gnome-builder.mk b/src/gnome-builder.mk
index 3fc3f49..31b5c97 100644
--- a/src/gnome-builder.mk
+++ b/src/gnome-builder.mk
@@ -113,6 +113,7 @@ libgnome_builder_la_SOURCES = \
 
 libgnome_builder_la_LIBADD = \
        $(DEVHELP_LIBS) \
+       $(GGIT_LIBS) \
        $(GIO_LIBS) \
        $(GTKSOURCEVIEW_LIBS) \
        $(GTK_LIBS) \
@@ -121,6 +122,7 @@ libgnome_builder_la_LIBADD = \
 
 libgnome_builder_la_CFLAGS = \
        $(DEVHELP_CFLAGS) \
+       $(GGIT_CFLAGS) \
        $(GIO_CFLAGS) \
        $(GTKSOURCEVIEW_CFLAGS) \
        $(GTK_CFLAGS) \
diff --git a/src/main.c b/src/main.c
index 3a43423..4834713 100644
--- a/src/main.c
+++ b/src/main.c
@@ -19,6 +19,7 @@
 #include <glib.h>
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
+#include <libgit2-glib/ggit.h>
 
 #include "gb-application.h"
 #include "gb-log.h"
@@ -34,6 +35,7 @@ main (int   argc,
   g_set_application_name (_("Builder"));
 
   gb_log_init (TRUE, NULL);
+  ggit_init ();
 
   app = g_object_new (GB_TYPE_APPLICATION,
                       "application-id", "org.gnome.Builder",


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