[anjuta] libanjuta/git: Render diffs one line at a time
- From: James Liggett <jrliggett src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta] libanjuta/git: Render diffs one line at a time
- Date: Mon, 9 Sep 2013 02:10:59 +0000 (UTC)
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]