[gnome-builder/wip/ggit] change-monitor: wire up diff callback using libgit2-glib.



commit 4c9324d4db4bd4ffbd76af01ad1451353182274e
Author: Christian Hergert <christian hergert me>
Date:   Sun Sep 28 22:51:44 2014 -0700

    change-monitor: wire up diff callback using libgit2-glib.
    
    This seems to mostly get things working using libgit2-glib instead of
    the built in monitor for the file.
    
    What we might consider doing next is when opening the file, determine
    which version to use. We can keep the old version around for files that
    are not yet in a source tree and this around for files that are in a
    source tree.
    
    Further refactoring necessary.

 src/editor/gb-source-change-gutter-renderer.c |   24 ++++-
 src/editor/gb-source-change-monitor.c         |  117 ++++++++++++++++++++++++-
 src/editor/gb-source-change-monitor.h         |    7 +-
 3 files changed, 138 insertions(+), 10 deletions(-)
---
diff --git a/src/editor/gb-source-change-gutter-renderer.c b/src/editor/gb-source-change-gutter-renderer.c
index 882f1cf..2d3598b 100644
--- a/src/editor/gb-source-change-gutter-renderer.c
+++ b/src/editor/gb-source-change-gutter-renderer.c
@@ -48,6 +48,18 @@ gb_source_change_gutter_renderer_get_change_monitor (GbSourceChangeGutterRendere
 }
 
 static void
+on_changed (GbSourceChangeMonitor        *monitor,
+            GbSourceChangeGutterRenderer *renderer)
+{
+  GtkTextView *text_view;
+
+  g_return_val_if_fail (GB_IS_SOURCE_CHANGE_GUTTER_RENDERER (renderer), NULL);
+
+  text_view = gtk_source_gutter_renderer_get_view (GTK_SOURCE_GUTTER_RENDERER (renderer));
+  gtk_widget_queue_draw (GTK_WIDGET (text_view));
+}
+
+static void
 gb_source_change_gutter_renderer_set_change_monitor (GbSourceChangeGutterRenderer *renderer,
                                                      GbSourceChangeMonitor        *monitor)
 {
@@ -60,6 +72,9 @@ gb_source_change_gutter_renderer_set_change_monitor (GbSourceChangeGutterRendere
 
   if (priv->change_monitor)
     {
+      g_signal_handlers_disconnect_by_func (priv->change_monitor,
+                                            G_CALLBACK (on_changed),
+                                            renderer);
       g_object_remove_weak_pointer (G_OBJECT (monitor),
                                     (gpointer *)&priv->change_monitor);
       priv->change_monitor = NULL;
@@ -70,6 +85,10 @@ gb_source_change_gutter_renderer_set_change_monitor (GbSourceChangeGutterRendere
       priv->change_monitor = monitor;
       g_object_add_weak_pointer (G_OBJECT (monitor),
                                  (gpointer *)&priv->change_monitor);
+      g_signal_connect (priv->change_monitor,
+                        "changed",
+                        G_CALLBACK (on_changed),
+                        renderer);
     }
 }
 
@@ -108,11 +127,6 @@ gb_source_change_gutter_renderer_draw (GtkSourceGutterRenderer      *renderer,
   if ((flags & GB_SOURCE_CHANGE_CHANGED) != 0)
     gdk_rgba_parse (&rgba, "#fcaf3e");
 
-  if ((flags & GB_SOURCE_CHANGE_DIRTY) == 0)
-    {
-      gdk_rgba_parse (&rgba, "rgb(179,208,238)");
-    }
-
   gdk_cairo_rectangle (cr, cell_area);
   gdk_cairo_set_source_rgba (cr, &rgba);
   cairo_fill (cr);
diff --git a/src/editor/gb-source-change-monitor.c b/src/editor/gb-source-change-monitor.c
index 5fe80ee..4d21994 100644
--- a/src/editor/gb-source-change-monitor.c
+++ b/src/editor/gb-source-change-monitor.c
@@ -25,7 +25,9 @@
 #include "gb-log.h"
 #include "gb-source-change-monitor.h"
 
-#define PARSE_TIMEOUT_MSEC 1000
+#define PARSE_TIMEOUT_MSEC       100
+#define GB_SOURCE_CHANGE_DELETED (1 << 3)
+#define GB_SOURCE_CHANGE_MASK    (0x7)
 
 struct _GbSourceChangeMonitorPrivate
 {
@@ -45,11 +47,18 @@ enum
   LAST_PROP
 };
 
+enum
+{
+  CHANGED,
+  LAST_SIGNAL
+};
+
 G_DEFINE_TYPE_WITH_PRIVATE (GbSourceChangeMonitor,
                             gb_source_change_monitor,
                             G_TYPE_OBJECT)
 
 static GParamSpec *gParamSpecs [LAST_PROP];
+static guint       gSignals [LAST_SIGNAL];
 
 GbSourceChangeFlags
 gb_source_change_monitor_get_line (GbSourceChangeMonitor *monitor,
@@ -57,22 +66,95 @@ gb_source_change_monitor_get_line (GbSourceChangeMonitor *monitor,
 {
   g_return_val_if_fail (GB_IS_SOURCE_CHANGE_MONITOR (monitor), 0);
 
+  /*
+   * We store line numbers as 1 based to simply the diff code.
+   */
+  lineno++;
+
   if (monitor->priv->state)
     {
       gpointer value;
 
       value = g_hash_table_lookup (monitor->priv->state,
                                    GINT_TO_POINTER (lineno));
-      return GPOINTER_TO_INT (value);
+      return (GPOINTER_TO_INT (value) & GB_SOURCE_CHANGE_MASK);
     }
 
   return GB_SOURCE_CHANGE_NONE;
 }
 
+static gint
+diff_line_cb (GgitDiffDelta *delta,
+              GgitDiffHunk  *hunk,
+              GgitDiffLine  *line,
+              gpointer       user_data)
+{
+  GgitDiffLineType type;
+  GHashTable *hash = user_data;
+  gint new_lineno;
+  gint old_lineno;
+  gint adjust;
+
+  g_return_val_if_fail (delta, GGIT_ERROR_GIT_ERROR);
+  g_return_val_if_fail (hunk, GGIT_ERROR_GIT_ERROR);
+  g_return_val_if_fail (line, GGIT_ERROR_GIT_ERROR);
+  g_return_val_if_fail (hash, GGIT_ERROR_GIT_ERROR);
+
+  type = ggit_diff_line_get_origin (line);
+
+  if ((type != GGIT_DIFF_LINE_ADDITION) && (type != GGIT_DIFF_LINE_DELETION))
+    return 0;
+
+  new_lineno = ggit_diff_line_get_new_lineno (line);
+  old_lineno = ggit_diff_line_get_old_lineno (line);
+
+  switch (type)
+    {
+    case GGIT_DIFF_LINE_ADDITION:
+      if (g_hash_table_lookup (hash, GINT_TO_POINTER (new_lineno)))
+        g_hash_table_replace (hash,
+                              GINT_TO_POINTER (new_lineno),
+                              GINT_TO_POINTER (GB_SOURCE_CHANGE_CHANGED));
+      else
+        g_hash_table_insert (hash,
+                             GINT_TO_POINTER (new_lineno),
+                             GINT_TO_POINTER (GB_SOURCE_CHANGE_ADDED));
+      break;
+
+    case GGIT_DIFF_LINE_DELETION:
+      adjust = (ggit_diff_hunk_get_new_start (hunk) -
+                ggit_diff_hunk_get_old_start (hunk));
+      old_lineno += adjust;
+      if (g_hash_table_lookup (hash, GINT_TO_POINTER (old_lineno)))
+        g_hash_table_replace (hash,
+                              GINT_TO_POINTER (old_lineno),
+                              GINT_TO_POINTER (GB_SOURCE_CHANGE_CHANGED));
+      else
+        g_hash_table_insert (hash,
+                             GINT_TO_POINTER (old_lineno),
+                             GINT_TO_POINTER (GB_SOURCE_CHANGE_DELETED));
+      break;
+
+    case GGIT_DIFF_LINE_CONTEXT:
+    case GGIT_DIFF_LINE_CONTEXT_EOFNL:
+    case GGIT_DIFF_LINE_ADD_EOFNL:
+    case GGIT_DIFF_LINE_DEL_EOFNL:
+    case GGIT_DIFF_LINE_FILE_HDR:
+    case GGIT_DIFF_LINE_HUNK_HDR:
+    case GGIT_DIFF_LINE_BINARY:
+    default:
+      break;
+    }
+
+  return 0;
+}
+
 static gboolean
 on_parse_timeout (GbSourceChangeMonitor *monitor)
 {
   GbSourceChangeMonitorPrivate *priv;
+  GtkTextIter begin;
+  GtkTextIter end;
   GgitOId *entry_oid = NULL;
   GgitOId *oid = NULL;
   GgitObject *blob = NULL;
@@ -83,6 +165,13 @@ on_parse_timeout (GbSourceChangeMonitor *monitor)
   GFile *workdir = NULL;
   GError *error = NULL;
   gchar *relpath = NULL;
+  gchar *text = NULL;
+
+  /*
+   * TODO: Move this to a worker thread!
+   *       We probably want to generate the ghashtable and then pass back that
+   *       new state to the main thread via an async worker func/cb.
+   */
 
   ENTRY;
 
@@ -145,6 +234,18 @@ on_parse_timeout (GbSourceChangeMonitor *monitor)
   if (!blob)
     GOTO (cleanup);
 
+  gtk_text_buffer_get_bounds (priv->buffer, &begin, &end);
+  text = gtk_text_buffer_get_text (priv->buffer, &begin, &end, TRUE);
+
+  ggit_diff_blob_to_buffer (GGIT_BLOB (blob), relpath, (const guint8 *)text,
+                            -1, relpath, NULL, NULL, NULL, diff_line_cb,
+                            (gpointer *)priv->state, &error);
+
+  if (error)
+    GOTO (cleanup);
+
+  g_signal_emit (monitor, gSignals [CHANGED], 0);
+
 cleanup:
   if (error)
     {
@@ -152,6 +253,7 @@ cleanup:
       g_clear_error (&error);
     }
 
+  g_clear_pointer (&text, g_free);
   g_clear_object (&blob);
   g_clear_pointer (&entry_oid, ggit_oid_free);
   g_clear_pointer (&entry, ggit_tree_entry_unref);
@@ -443,6 +545,17 @@ gb_source_change_monitor_class_init (GbSourceChangeMonitorClass *klass)
                           G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (object_class, PROP_FILE,
                                    gParamSpecs [PROP_FILE]);
+
+  gSignals [CHANGED] =
+    g_signal_new ("changed",
+                  GB_TYPE_SOURCE_CHANGE_MONITOR,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GbSourceChangeMonitorClass, changed),
+                  NULL,
+                  NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE,
+                  0);
 }
 
 static void
diff --git a/src/editor/gb-source-change-monitor.h b/src/editor/gb-source-change-monitor.h
index b1bebe9..522ac9a 100644
--- a/src/editor/gb-source-change-monitor.h
+++ b/src/editor/gb-source-change-monitor.h
@@ -38,9 +38,8 @@ 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,
+  GB_SOURCE_CHANGE_ADDED   = 1 << 0,
+  GB_SOURCE_CHANGE_CHANGED = 1 << 1,
 } GbSourceChangeFlags;
 
 struct _GbSourceChangeMonitor
@@ -54,6 +53,8 @@ struct _GbSourceChangeMonitor
 struct _GbSourceChangeMonitorClass
 {
   GObjectClass parent_class;
+
+  void (*changed) (GbSourceChangeMonitor *monitor);
 };
 
 GType                  gb_source_change_monitor_get_type (void) G_GNUC_CONST;


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