[libgit2-glib] Implement ggit_diff_line_get_text



commit d40bb525c9307af6ccfe9c3cc1fee6a2f16b52b3
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Fri Dec 27 16:20:10 2013 +0100

    Implement ggit_diff_line_get_text
    
    Retrieve the encoding of a file from either the gui.encoding config
    value, or (with higher priority) the encoding file attribute. If set,
    ggit_diff_line_get_text will convert from that encoding to utf-8 and
    ensures a utf-8 encoded string is returned. Characters that cannot be
    decoded will contain the fallback ? character.

 libgit2-glib/ggit-diff-line.c |   34 +++++++-
 libgit2-glib/ggit-diff-line.h |    5 +-
 libgit2-glib/ggit-diff.c      |  187 +++++++++++++++++++++++++++++++++++++----
 libgit2-glib/ggit-diff.h      |    7 +-
 4 files changed, 210 insertions(+), 23 deletions(-)
---
diff --git a/libgit2-glib/ggit-diff-line.c b/libgit2-glib/ggit-diff-line.c
index f135856..6c78b0d 100644
--- a/libgit2-glib/ggit-diff-line.c
+++ b/libgit2-glib/ggit-diff-line.c
@@ -22,6 +22,7 @@
 #include <git2.h>
 
 #include "ggit-diff-line.h"
+#include "ggit-convert.h"
 
 struct _GgitDiffLine {
        gint ref_count;
@@ -33,6 +34,9 @@ struct _GgitDiffLine {
        gsize content_len;
        gint64 content_offset;
        const gchar *content;
+
+       gchar *text;
+       const gchar *encoding;
 };
 
 G_DEFINE_BOXED_TYPE (GgitDiffLine, ggit_diff_line,
@@ -40,7 +44,8 @@ G_DEFINE_BOXED_TYPE (GgitDiffLine, ggit_diff_line,
 
 
 GgitDiffLine *
-_ggit_diff_line_wrap (const git_diff_line *line)
+_ggit_diff_line_wrap (const git_diff_line *line,
+                      const gchar         *encoding)
 {
        GgitDiffLine *gline;
 
@@ -54,6 +59,8 @@ _ggit_diff_line_wrap (const git_diff_line *line)
        gline->content_len = line->content_len;
        gline->content_offset = line->content_offset;
        gline->content = line->content;
+       gline->encoding = encoding;
+       gline->text = NULL;
 
        return gline;
 }
@@ -91,6 +98,7 @@ ggit_diff_line_unref (GgitDiffLine *line)
 
        if (g_atomic_int_dec_and_test (&line->ref_count))
        {
+               g_free (line->text);
                g_slice_free (GgitDiffLine, line);
        }
 }
@@ -182,4 +190,28 @@ ggit_diff_line_get_content (GgitDiffLine *line,
        return (const guint8 *)line->content;
 }
 
+/**
+ * ggit_diff_line_get_text:
+ * @line: a #GgitDiffLine.
+ *
+ * Get the content of the diff line as UTF-8 encoded text.
+ *
+ * Returns: the content in utf-8 encoding.
+ *
+ **/
+const gchar *
+ggit_diff_line_get_text (GgitDiffLine *line)
+{
+       g_return_val_if_fail (line != NULL, NULL);
+
+       if (line->text == NULL)
+       {
+               line->text = ggit_convert_utf8 (line->content,
+                                               line->content_len,
+                                               line->encoding);
+       }
+
+       return line->text;
+}
+
 /* ex:set ts=8 noet: */
diff --git a/libgit2-glib/ggit-diff-line.h b/libgit2-glib/ggit-diff-line.h
index f055187..2181937 100644
--- a/libgit2-glib/ggit-diff-line.h
+++ b/libgit2-glib/ggit-diff-line.h
@@ -30,7 +30,8 @@ G_BEGIN_DECLS
 
 GType             ggit_diff_line_get_type           (void) G_GNUC_CONST;
 
-GgitDiffLine     *_ggit_diff_line_wrap              (const git_diff_line *line);
+GgitDiffLine     *_ggit_diff_line_wrap              (const git_diff_line *line,
+                                                     const gchar         *encoding);
 
 GgitDiffLine     *ggit_diff_line_ref                (GgitDiffLine        *line);
 void              ggit_diff_line_unref              (GgitDiffLine        *line);
@@ -43,6 +44,8 @@ gint64            ggit_diff_line_get_content_offset (GgitDiffLine        *line);
 const guint8     *ggit_diff_line_get_content        (GgitDiffLine        *line,
                                                      gsize               *length);
 
+const gchar      *ggit_diff_line_get_text           (GgitDiffLine        *line);
+
 G_END_DECLS
 
 #endif /* __GGIT_DIFF_LINE_H__ */
diff --git a/libgit2-glib/ggit-diff.c b/libgit2-glib/ggit-diff.c
index 7580d8b..143068c 100644
--- a/libgit2-glib/ggit-diff.c
+++ b/libgit2-glib/ggit-diff.c
@@ -28,8 +28,20 @@
 #include "ggit-patch.h"
 #include "ggit-error.h"
 #include "ggit-repository.h"
+#include "ggit-diff-file.h"
+
+#define GGIT_DIFF_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GGIT_TYPE_DIFF, GgitDiffPrivate))
+
+struct _GgitDiffPrivate
+{
+       GgitRepository *repository;
+       gchar *encoding;
+};
 
 typedef struct {
+       GgitDiff *diff;
+       const gchar *encoding;
+
        gpointer user_data;
 
        GgitDiffFileCallback file_cb;
@@ -39,6 +51,12 @@ typedef struct {
 
 G_DEFINE_TYPE (GgitDiff, ggit_diff, GGIT_TYPE_NATIVE)
 
+enum
+{
+       PROP_0,
+       PROP_REPOSITORY
+};
+
 static gint
 ggit_diff_file_callback_wrapper (const git_diff_delta *delta,
                                  gfloat                progress,
@@ -50,6 +68,36 @@ ggit_diff_file_callback_wrapper (const git_diff_delta *delta,
 
        gdelta = _ggit_diff_delta_wrap (delta);
 
+       data->encoding = NULL;
+
+       if (data->diff != NULL)
+       {
+               GgitDiffFile *file;
+
+               if (ggit_diff_delta_get_status (gdelta) == GGIT_DELTA_DELETED)
+               {
+                       file = ggit_diff_delta_get_old_file (gdelta);
+               }
+               else
+               {
+                       file = ggit_diff_delta_get_new_file (gdelta);
+               }
+
+               if (file != NULL)
+               {
+                       const gchar *path;
+
+                       path = ggit_diff_file_get_path (file);
+
+                       data->encoding =
+                               ggit_repository_get_attribute (data->diff->priv->repository,
+                                                              path,
+                                                              "encoding",
+                                                              GGIT_ATTRIBUTE_CHECK_FILE_THEN_INDEX,
+                                                              NULL);
+               }
+       }
+
        ret = data->file_cb (gdelta, progress, data->user_data);
 
        ggit_diff_delta_unref (gdelta);
@@ -89,10 +137,20 @@ ggit_diff_line_callback_wrapper (const git_diff_delta *delta,
        GgitDiffHunk *ghunk;
        GgitDiffLine *gline;
        gint ret;
+       const gchar *encoding = NULL;
+
+       if (data->encoding != NULL)
+       {
+               encoding = data->encoding;
+       }
+       else if (data->diff != NULL)
+       {
+               encoding = data->diff->priv->encoding;
+       }
 
        gdelta = _ggit_diff_delta_wrap (delta);
        ghunk = hunk == NULL ? NULL : _ggit_diff_hunk_wrap (hunk);
-       gline = line == NULL ? NULL : _ggit_diff_line_wrap (line);
+       gline = line == NULL ? NULL : _ggit_diff_line_wrap (line, encoding);
 
        ret = data->line_cb (gdelta, ghunk, gline, data->user_data);
 
@@ -112,29 +170,117 @@ ggit_diff_line_callback_wrapper (const git_diff_delta *delta,
 }
 
 static void
-ggit_diff_class_init (GgitDiffClass *klass)
+ggit_diff_finalize (GObject *object)
 {
+       GgitDiffPrivate *priv = GGIT_DIFF (object)->priv;
+
+       g_free (priv->encoding);
+
+       G_OBJECT_CLASS (ggit_diff_parent_class)->finalize (object);
 }
 
 static void
-ggit_diff_init (GgitDiff *self)
+ggit_diff_set_property (GObject      *object,
+                        guint         prop_id,
+                        const GValue *value,
+                        GParamSpec   *pspec)
 {
+       GgitDiff *self = GGIT_DIFF (object);
+
+       switch (prop_id)
+       {
+       case PROP_REPOSITORY:
+               self->priv->repository = g_value_dup_object (value);
+               break;
+       default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
 }
 
-GgitDiff *
-_ggit_diff_wrap (git_diff *diff,
-                 gboolean  owned)
+static void
+ggit_diff_get_property (GObject    *object,
+                        guint       prop_id,
+                        GValue     *value,
+                        GParamSpec *pspec)
 {
-       GgitDiff *gdiff;
+       GgitDiff *self = GGIT_DIFF (object);
 
-       gdiff = g_object_new (GGIT_TYPE_DIFF, NULL);
-       _ggit_native_set (gdiff, diff, NULL);
+       switch (prop_id)
+       {
+       case PROP_REPOSITORY:
+               g_value_set_object (value, self->priv->repository);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
 
-       if (owned)
+static void
+ggit_diff_constructed (GObject *object)
+{
+       GgitDiffPrivate *priv = GGIT_DIFF (object)->priv;
+       GgitConfig *config = NULL;
+
+       if (priv->repository != NULL)
        {
-               _ggit_native_set_destroy_func (gdiff,
-                                              (GDestroyNotify)git_diff_free);
+               config = ggit_repository_get_config (priv->repository, NULL);
+       }
+
+       if (config != NULL)
+       {
+               const gchar *enc;
+
+               enc = ggit_config_get_string (config, "gui.encoding", NULL);
+
+               if (enc != NULL)
+               {
+                       priv->encoding = g_strdup (enc);
+               }
+
+               g_object_unref (config);
        }
+}
+
+static void
+ggit_diff_class_init (GgitDiffClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = ggit_diff_finalize;
+       object_class->constructed = ggit_diff_constructed;
+
+       object_class->get_property = ggit_diff_get_property;
+       object_class->set_property = ggit_diff_set_property;
+
+       g_object_class_install_property (object_class,
+                                        PROP_REPOSITORY,
+                                        g_param_spec_object ("repository",
+                                                             "Repository",
+                                                             "Repository",
+                                                             GGIT_TYPE_REPOSITORY,
+                                                             G_PARAM_READWRITE |
+                                                             G_PARAM_CONSTRUCT_ONLY |
+                                                             G_PARAM_STATIC_STRINGS));
+
+       g_type_class_add_private (object_class, sizeof (GgitDiffPrivate));
+}
+
+static void
+ggit_diff_init (GgitDiff *self)
+{
+       self->priv = GGIT_DIFF_GET_PRIVATE (self);
+}
+
+static GgitDiff *
+_ggit_diff_wrap (GgitRepository *repository,
+                 git_diff       *diff)
+{
+       GgitDiff *gdiff;
+
+       gdiff = g_object_new (GGIT_TYPE_DIFF, "repository", repository, NULL);
+       _ggit_native_set (gdiff, diff, (GDestroyNotify)git_diff_free);
 
        return gdiff;
 }
@@ -182,7 +328,7 @@ ggit_diff_new_tree_to_tree (GgitRepository   *repository,
                return NULL;
        }
 
-       return _ggit_diff_wrap (diff, TRUE);
+       return _ggit_diff_wrap (repository, diff);
 }
 
 /**
@@ -228,7 +374,7 @@ ggit_diff_new_tree_to_index (GgitRepository   *repository,
                return NULL;
        }
 
-       return _ggit_diff_wrap (diff, TRUE);
+       return _ggit_diff_wrap (repository, diff);
 }
 
 /**
@@ -270,7 +416,7 @@ ggit_diff_new_index_to_workdir (GgitRepository   *repository,
                return NULL;
        }
 
-       return _ggit_diff_wrap (diff, TRUE);
+       return _ggit_diff_wrap (repository, diff);
 }
 
 /**
@@ -311,7 +457,7 @@ ggit_diff_new_tree_to_workdir (GgitRepository   *repository,
                return NULL;
        }
 
-       return _ggit_diff_wrap (diff, TRUE);
+       return _ggit_diff_wrap (repository, diff);
 }
 
 /**
@@ -375,6 +521,8 @@ ggit_diff_foreach (GgitDiff              *diff,
        g_return_if_fail (error == NULL || *error == NULL);
 
        wrapper_data.user_data = user_data;
+       wrapper_data.diff = diff;
+       wrapper_data.encoding = NULL;
 
        if (file_cb != NULL)
        {
@@ -429,6 +577,9 @@ ggit_diff_print (GgitDiff              *diff,
        g_return_if_fail (error == NULL || *error == NULL);
 
        wrapper_data.user_data = user_data;
+       wrapper_data.diff = diff;
+       wrapper_data.encoding = NULL;
+
        wrapper_data.line_cb = print_cb;
 
        ret = git_diff_print (_ggit_native_get (diff), (git_diff_format_t)type,
@@ -506,6 +657,8 @@ ggit_diff_blobs (GgitBlob              *old_blob,
        gdiff_options = _ggit_diff_options_get_diff_options (diff_options);
 
        wrapper_data.user_data = user_data;
+       wrapper_data.diff = NULL;
+       wrapper_data.encoding = NULL;
 
        if (file_cb != NULL)
        {
@@ -583,6 +736,8 @@ ggit_diff_blob_to_buffer (GgitBlob              *old_blob,
        gdiff_options = _ggit_diff_options_get_diff_options (diff_options);
 
        wrapper_data.user_data = user_data;
+       wrapper_data.diff = NULL;
+       wrapper_data.encoding = NULL;
 
        if (file_cb != NULL)
        {
diff --git a/libgit2-glib/ggit-diff.h b/libgit2-glib/ggit-diff.h
index 169a494..1c39bcb 100644
--- a/libgit2-glib/ggit-diff.h
+++ b/libgit2-glib/ggit-diff.h
@@ -35,14 +35,14 @@ G_BEGIN_DECLS
 #define GGIT_DIFF_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GGIT_TYPE_DIFF, GgitDiffClass))
 
 typedef struct _GgitDiffClass  GgitDiffClass;
+typedef struct _GgitDiffPrivate GgitDiffPrivate;
 
 struct _GgitDiff
 {
        /*< private >*/
        GgitNative parent;
 
-       /* priv padding */
-       gpointer priv;
+       GgitDiffPrivate *priv;
 };
 
 /**
@@ -59,9 +59,6 @@ struct _GgitDiffClass
 
 GType          ggit_diff_get_type                  (void) G_GNUC_CONST;
 
-GgitDiff      *_ggit_diff_wrap                     (git_diff              *diff,
-                                                    gboolean               owned);
-
 GgitDiff      *ggit_diff_new_tree_to_tree          (GgitRepository        *repository,
                                                     GgitTree              *old_tree,
                                                     GgitTree              *new_tree,


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