[anjuta] libanjuta/git: Render diffs one line at a time



commit a2491547d1e626e2d4d954a158653a0b3b1688ec
Author: James Liggett <jrliggett cox net>
Date:   Sun Sep 8 19:10:19 2013 -0700

    libanjuta/git: Render diffs one line at a time
    
    Rendering is very slow on large diffs when we try to render a whole diff
    in one cell renderer. Splitting up the diffs into individual lines makes
    rendering much faster.

 libanjuta/anjuta-cell-renderer-diff.c       |  149 +++++++++++++++------------
 libanjuta/tests/anjuta-diff-renderer-test.c |  102 +++++++++----------
 plugins/git/git-diff-command.c              |    1 +
 plugins/git/git-stash-pane.c                |   23 +++--
 plugins/git/git-stash-show-command.c        |    1 +
 plugins/git/git-status-pane.c               |   13 +--
 6 files changed, 155 insertions(+), 134 deletions(-)
---
diff --git a/libanjuta/anjuta-cell-renderer-diff.c b/libanjuta/anjuta-cell-renderer-diff.c
index f69d47b..019ff7d 100644
--- a/libanjuta/anjuta-cell-renderer-diff.c
+++ b/libanjuta/anjuta-cell-renderer-diff.c
@@ -33,6 +33,15 @@ enum
 };
 
 
+/* Line types */
+typedef enum
+{
+       LINE_TYPE_HEADER,
+       LINE_TYPE_HUNK_HEADER,
+       LINE_TYPE_ADD,
+       LINE_TYPE_DELETE,
+       LINE_TYPE_CONTEXT
+} LineType;
 
 G_DEFINE_TYPE (AnjutaCellRendererDiff, anjuta_cell_renderer_diff, GTK_TYPE_CELL_RENDERER);
 
@@ -146,80 +155,67 @@ static PangoAttrList *
 create_attribute_list (const gchar *diff)
 {
        PangoAttrList *list;
-       const gchar *line_begin, *line_end;
-       guint begin_index, end_index;
-       gboolean found_diff = FALSE;
-       gboolean found_hunk = FALSE;
-       PangoAttribute *attribute;
+       LineType type;
 
        list = pango_attr_list_new ();
 
        /* Make all of the text monospace */
        pango_attr_list_insert (list, pango_attr_family_new ("Monospace"));
 
-       line_begin = diff;
-
-       while (line_begin && *line_begin)
+       /* Assume that diff points to one line of a unified diff */
+       type = LINE_TYPE_CONTEXT;
+       
+       if (diff && diff[0])
        {
-               line_end = strchr (line_begin, '\n');
-
-               if (!line_end)
-                       line_end = diff + strlen (line_begin);
-
-               begin_index = line_begin - diff;
-               end_index = line_end - diff;
-               attribute = NULL;
-
-               /* Handle multiple files. Context lines should start with a 
-                * whitespace, so just searching the first few characters 
-                * of the line for "diff" should detect the next file */
-               if (g_str_has_prefix (line_begin, "diff"))
-               {
-                       found_diff = TRUE;
-                       found_hunk = FALSE;
-               }
-
-               if (line_begin[0] == '@' && line_begin[1] == '@')
-               {
-                       /* Dark blue */
-                       attribute = pango_attr_foreground_new (0, 0, 0x8000);
-
-                       /* Don't decorate diff headers */
-                       found_hunk = TRUE;
-               }
-               else if (found_hunk)
+               if (*diff != ' ')
                {
-                       if (line_begin[0] == '+')
+                       if (diff[0] == '@' && diff[1] == '@')
+                               type = LINE_TYPE_HUNK_HEADER;
+                       else if (diff[0] == '+')
                        {
-                               /* Dark green */
-                               attribute = pango_attr_foreground_new (0, 0x8000, 0);
+                               if (g_str_has_prefix (diff, "+++ "))
+                                   type = LINE_TYPE_HEADER;
+                               else
+                                       type = LINE_TYPE_ADD;
                        }
-                       else if (line_begin[0] == '-')
+                       else if (diff[0] == '-')
                        {
-                               /* Red */
-                               attribute = pango_attr_foreground_new (0xffff, 0, 0);   
+                               if (g_str_has_prefix (diff, "--- "))
+                                       type = LINE_TYPE_HEADER;
+                               else
+                                       type = LINE_TYPE_DELETE;
                        }
+                       else
+                               type = LINE_TYPE_HEADER;
                }
-               else if (found_diff)
-               {
-                       /* Make file headers easier to see by making them bold */
-                       attribute = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
-               }
-                       
-               if (attribute)
-               {
-                       attribute->start_index = begin_index;
-                       attribute->end_index = end_index;
-
-                       pango_attr_list_insert (list, attribute);
-               }
-
-               if (*line_end)
-                       line_begin = line_end + 1;
-               else
-                       line_begin = NULL;
        }
 
+       switch (type)
+       {
+               case LINE_TYPE_HEADER:
+                       /* Make file headers easier to see by making them bold */
+                       pango_attr_list_insert (list, 
+                                               pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+                       break;
+               case LINE_TYPE_HUNK_HEADER:
+                       /* Dark blue */
+                       pango_attr_list_insert (list, 
+                                               pango_attr_foreground_new (0, 0, 0x8000));
+                       break;
+               case LINE_TYPE_ADD:
+                       /* Dark green */
+                       pango_attr_list_insert (list, 
+                                               pango_attr_foreground_new (0, 0x8000, 0));
+                       break;
+               case LINE_TYPE_DELETE:
+                       /* Red */
+                       pango_attr_list_insert (list, 
+                                               pango_attr_foreground_new (0xffff, 0, 0));
+                       break;
+               default:
+                       break;
+       };
+
        return list;
 }
 
@@ -228,16 +224,41 @@ anjuta_cell_renderer_diff_set_diff (AnjutaCellRendererDiff *self,
                                     const gchar *diff)
 {
        PangoAttrList *attributes = NULL;
+       gchar *newline;
+       gchar *diff_without_newline = NULL;
 
        if (diff)
+       {
+               newline = strchr (diff, '\n');
+
+               if (newline)
+               {
+                       diff_without_newline = g_strndup (diff, newline - diff);
+                       g_object_set (G_OBJECT (self->priv->text_cell),
+                                               "text", diff_without_newline,
+                                               NULL);
+                       g_free (diff_without_newline);
+               }
+               else
+               {
+                       g_object_set (G_OBJECT (self->priv->text_cell),
+                                     "text", diff,
+                                     NULL);
+               }
+
                attributes = create_attribute_list (diff);
 
-       g_object_set (G_OBJECT (self->priv->text_cell),
-                     "attributes", attributes, 
-                     "text", diff, 
-                     NULL);
+               g_object_set (G_OBJECT (self->priv->text_cell),
+                                 "attributes", attributes,
+                             NULL);
 
-       pango_attr_list_unref (attributes);
+               pango_attr_list_unref (attributes);
+       }
+       else
+       {
+               g_object_set (G_OBJECT (self->priv->text_cell),
+                             "text", "", NULL);
+       }
 }
 
 GtkCellRenderer *
diff --git a/libanjuta/tests/anjuta-diff-renderer-test.c b/libanjuta/tests/anjuta-diff-renderer-test.c
index 563f4c0..f54b3a7 100644
--- a/libanjuta/tests/anjuta-diff-renderer-test.c
+++ b/libanjuta/tests/anjuta-diff-renderer-test.c
@@ -42,53 +42,31 @@ main (int argc, char **argv)
        GtkCellRenderer *renderer;
        GtkListStore *list_store;
        GtkTreeIter iter;
-       const gchar diff[] = 
-               "diff --git a/libanjuta/Makefile.am b/libanjuta/Makefile.am\n"
-               "index 4ac227e..d47c978 100644\n"
-               "--- a/libanjuta/Makefile.am\n"
-               "+++ b/libanjuta/Makefile.am\n"
-               "@@ -138,7 +138,9 @@ libanjuta_3_la_SOURCES= \\\n"
-               "        anjuta-close-button.c \\\n"
-               "        anjuta-close-button.h \\\n"
-               "        anjuta-modeline.c \\\n"
-               "-       anjuta-modeline.h\n"
-               "+       anjuta-modeline.h \\\n"
-               "+       anjuta-cell-renderer-diff.c \\\n"
-               "+       anjuta-cell-renderer-diff.h\n"
-               "\n"
-               "# Glade module\n"
-               "if ENABLE_GLADE_CATALOG\n";
-       
-       const gchar multi_file_diff[] =
-               "diff --git a/AUTHORS b/AUTHORS\n"
-               "index 9f20595..7f6ead6 100644\n"
-               "--- a/AUTHORS\n"
-               "+++ b/AUTHORS\n"
-               "@@ -11,7 +11,7 @@ Maintainers and Lead Developers:\n"
-               " Developers:\n"
-               "-------------------------------------------------------------------------------\n"
-               "       Massimo Cora'  <maxcvs email it> (Italy)\n"
-               "-      Carl-Anton Ingmarsson <ca ingmarsson gmail com>\n"      
-               "+      Carl-Anton Ingmarsson <carlantoni gnome org> (Sweden)\n"
-               "\n"
-               " Past Developers:\n"
-               "-------------------------------------------------------------------------------\n"
-               "diff --git a/plugins/git/git-clone-command.c b/plugins/git/git-clone-command.c\n"
-               "index 8fbb96a..f1665e2 100644\n"
-               "--- a/plugins/git/git-clone-command.c\n"
-               "+++ b/plugins/git/git-clone-command.c\n"
-               "@@ -1,7 +1,7 @@\n"
-               " /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */\n"
-               " /*\n"
-               "  * anjuta\n"
-               "- * Copyright (C) Carl-Anton Ingmarsson 2009 <ca ingmarsson gmail com>\n"
-               "+ * Copyright (C) Carl-Anton Ingmarsson 2009 <carlantoni gnome org>\n"
-               "  *\n" 
-               "  * anjuta is free software.\n"
-               "  *\n";
+       const gchar header1[] =
+               "diff --git a/libanjuta/Makefile.am b/libanjuta/Makefile.am\n";
+
+       const gchar header2[] =
+               "index 4ac227e..d47c978 100644\n";
+
+       const gchar header3[] =
+               "--- a/libanjuta/Makefile.am\n";
+
+       const gchar header4[] = 
+               "+++ b/libanjuta/Makefile.am\n";
+
+       const gchar hunk_header[] =
+               "@@ -138,7 +138,9 @@ libanjuta_3_la_SOURCES= \\\n";
+
+       const gchar context[] =
+               "        anjuta-close-button.c \\\n";
+
+       const gchar add[] =
+               "+       anjuta-modeline.h \\\n";
+
+       const gchar delete[] =
+               "-       anjuta-modeline.h\n";
 
        const gchar non_diff[] = "non-diff text";
-       const gchar hunk_line[] = "@@";
        const gchar broken_hunk[] = "@";
 
        gtk_init (&argc, &argv);
@@ -114,22 +92,40 @@ main (int argc, char **argv)
 
        list_store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING);
 
-       /* Test general diffs */
+       /* Test headers*/
        gtk_list_store_append (list_store, &iter);
-       gtk_list_store_set (list_store, &iter, COL_DIFF, diff, -1);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, header1, -1);
 
-       /* Test multi-file diffs */
        gtk_list_store_append (list_store, &iter);
-       gtk_list_store_set (list_store, &iter, COL_DIFF, multi_file_diff, -1);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, header2, -1);
 
-       /* Test non-diff text */
        gtk_list_store_append (list_store, &iter);
-       gtk_list_store_set (list_store, &iter, COL_DIFF, non_diff, -1);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, header3, -1);
+
+       gtk_list_store_append (list_store, &iter);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, header4, -1);
 
-       /* Test hunk line detection */
+       /* Test hunk headers */
        gtk_list_store_append (list_store, &iter);
-       gtk_list_store_set (list_store, &iter, COL_DIFF, hunk_line, -1);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, hunk_header, -1);
+
+       /* Context lines */
+       gtk_list_store_append (list_store, &iter);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, context, -1);
+
+       /* Add */
+       gtk_list_store_append (list_store, &iter);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, add, -1);
+
+       /* Delete */
+       gtk_list_store_append (list_store, &iter);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, delete, -1);
+
+       /* Test non-diff text */
+       gtk_list_store_append (list_store, &iter);
+       gtk_list_store_set (list_store, &iter, COL_DIFF, non_diff, -1);
 
+       /* Test broken hunks */
        gtk_list_store_append (list_store, &iter);
        gtk_list_store_set (list_store, &iter, COL_DIFF, broken_hunk, -1);
 
diff --git a/plugins/git/git-diff-command.c b/plugins/git/git-diff-command.c
index 14f5446..d5b7682 100644
--- a/plugins/git/git-diff-command.c
+++ b/plugins/git/git-diff-command.c
@@ -88,6 +88,7 @@ git_diff_command_new (const gchar *working_directory, const gchar *path,
 
        self = g_object_new (GIT_TYPE_DIFF_COMMAND, 
                                                 "working-directory", working_directory,
+                            "single-line-output", TRUE,
                                                 NULL);
 
        self->priv->path = g_strdup (path);
diff --git a/plugins/git/git-stash-pane.c b/plugins/git/git-stash-pane.c
index 1ed42a0..6de5988 100644
--- a/plugins/git/git-stash-pane.c
+++ b/plugins/git/git-stash-pane.c
@@ -69,25 +69,30 @@ on_stash_diff_command_finished (AnjutaCommand *command, guint return_code,
                                 GtkTreeStore *stash_model)
 {
        GtkTreePath *parent_path;
-       GString *string;
        GtkTreeIter parent_iter;
        GtkTreeIter iter;
+       GQueue *output;
+       gchar *output_line;
 
        if (return_code == 0)
        {
-               string = g_string_new ("");
-               git_pane_send_raw_output_to_string (command, string);
-
                parent_path = g_object_get_data (G_OBJECT (command), "parent-path");
                gtk_tree_model_get_iter (GTK_TREE_MODEL (stash_model), &parent_iter,
                                         parent_path);
 
-               gtk_tree_store_append (stash_model, &iter, &parent_iter);
-               gtk_tree_store_set (stash_model, &iter,
-                                   COL_DIFF, string->str,
-                                   -1);
+               output = git_raw_output_command_get_output (GIT_RAW_OUTPUT_COMMAND (command));
 
-               g_string_free (string, TRUE);
+               while (g_queue_peek_head (output))
+               {
+                       output_line = g_queue_pop_head (output);
+
+                       gtk_tree_store_append (stash_model, &iter, &parent_iter);
+                       gtk_tree_store_set (stash_model, &iter,
+                                           COL_DIFF, output_line,
+                                           -1);
+
+                       g_free (output_line);
+               }
        }
 }
 
diff --git a/plugins/git/git-stash-show-command.c b/plugins/git/git-stash-show-command.c
index 66f9a4a..971a8df 100644
--- a/plugins/git/git-stash-show-command.c
+++ b/plugins/git/git-stash-show-command.c
@@ -84,6 +84,7 @@ git_stash_show_command_new (const gchar *working_directory, const gchar *stash)
        
        self =  g_object_new (GIT_TYPE_STASH_SHOW_COMMAND, 
                                                  "working-directory", working_directory,
+                             "single-line-output", TRUE,
                                                  NULL);
        
        self->priv->stash = g_strdup (stash);
diff --git a/plugins/git/git-status-pane.c b/plugins/git/git-status-pane.c
index 90e35f4..1419d20 100644
--- a/plugins/git/git-status-pane.c
+++ b/plugins/git/git-status-pane.c
@@ -355,7 +355,6 @@ on_diff_command_finished (AnjutaCommand *command, guint return_code,
        GtkTreePath *parent_path;
        GtkTreeIter parent_iter;
        GtkTreeIter iter;
-       GString *string;
        GQueue *output;
        gchar *output_line;
 
@@ -364,27 +363,25 @@ on_diff_command_finished (AnjutaCommand *command, guint return_code,
                status_model = g_object_get_data (G_OBJECT (command), "model");
                parent_path = g_object_get_data (G_OBJECT (command), "parent-path");
                gtk_tree_model_get_iter (status_model, &parent_iter, parent_path);
-               string = g_string_new ("");
                output = git_raw_output_command_get_output (GIT_RAW_OUTPUT_COMMAND (command));
 
                while (g_queue_peek_head (output))
                {
                        output_line = g_queue_pop_head (output);
-                       g_string_append (string, output_line);
+                       gtk_tree_store_append (GTK_TREE_STORE (status_model), &iter, &parent_iter);
+                       gtk_tree_store_set (GTK_TREE_STORE (status_model), &iter, 
+                                           COL_DIFF, output_line, 
+                                           -1);
 
                        g_free (output_line);
                }
 
-               gtk_tree_store_append (GTK_TREE_STORE (status_model), &iter, &parent_iter);
-               gtk_tree_store_set (GTK_TREE_STORE (status_model), &iter, COL_DIFF, string->str, -1);
+               
 
                g_hash_table_remove (self->priv->diff_commands, command);
                
                if (g_hash_table_size (self->priv->diff_commands) == 0)
                        git_status_pane_set_model (self);
-                       
-               g_string_free (string, TRUE);
-               
        }
 }
 


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