Skip to contentSkip to conversation

graph API: Added logic for colored edges

PATCH Superseded Allan Caffee 3 participants 13 messages Jun 15, 2016 1 message not in the archive

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

PATCH 1/1 graph API: Added logic for colored edges

Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk.

---
It seemed like it was time for another iteration so here it is. Changes this round include: (Only the first two were actually posted to the list as full patches.)

* graph.c: avoid compile warnings (Thanks Johannes)

* --graph: respect --no-color (Thanks Johannes)

* Remove some outdated TODO comments

* Avoid using forward declarations

* Remove commented out debugging code

* Avoid an unnecessary function call

* Refactor/rename some local functions
I replaced get_next_column_column color with graph_increment_column_color since the return value is never actually used. I also renamed get_current_column_color to graph_get_current_column_color.

* Handle column colors as const pointers
The color codes used should never be modified once we begin graphing, so columns should store/handle them as const char*.

* graph API: Add handling for merges with 3+ parents I accidentally left this one out of the first round.

~Allan

 color.h |    1 +
 graph.c |  175 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 145 insertions(+), 31 deletions(-)
color.h +1 -0
index 6846be1..18abeb7 100644
@@ -11,6 +11,7 @@
 #define GIT_COLOR_GREEN		"\033[32m"
 #define GIT_COLOR_YELLOW	"\033[33m"
 #define GIT_COLOR_BLUE		"\033[34m"
+#define GIT_COLOR_MAGENTA	"\033[35m"
 #define GIT_COLOR_CYAN		"\033[36m"
 #define GIT_COLOR_BG_RED	"\033[41m"
 
graph.c +144 -31

320 lines not on this page · raw message

Signature · 1 line
1.5.6.3
#2 lore raw

graph.c struct column { · line 74

Quoted 9 lines · Allan Caffee
graph.c +2 -2
@@ -72,11 +69,21 @@ struct column {
 	 */
 	struct commit *commit;
 	/*
-	 * XXX: Once we add support for colors, struct column could also
-	 * contain the color of its branch line.
+	 * The color to (optionally) print this column in.
 	 */
+	const char *color;

You already use short for git_graph.default_column_color and I suspect in the longer term you want to make this one an index into column_colors[] array the same way. We may someday decide to support non-ANSI color scheme using ncurses or something, and at that point the "hardware color" constants like GIT_COLOR_RED and friends may change from strings to small integers we use to call our (yet to be written) curses interface layer with.

graph.c static struct commit_list *first_interesting_parent(struct git_graph *graph) · line 346

Quoted 5 lines
graph.c +1 -0
@@ -312,6 +343,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph)
 	return next_interesting_parent(graph, parents);
 }
 
+static const char* graph_get_current_column_color(const struct git_graph* graph)

Style. Asterisk comes next to identifiers, not types (the parameter to graph_increment_column_color has the same issue).

static const char *graph_...color(const struct git_graph *graph)

graph.c static void graph_output_padding_line(struct git_graph *graph, · line 664

Quoted 6 lines
graph.c +1 -1
@@ -596,7 +661,7 @@ static void graph_output_padding_line(struct git_graph *graph,
 	 * Output a padding row, that leaves all branch lines unchanged
 	 */
 	for (i = 0; i < graph->num_new_columns; i++) {
-		strbuf_addstr(sb, "| ");
+		strbuf_write_column(sb, &graph->new_columns[i], "| ");

Hmmm, this forbids us to use reverse color in the color palette because that would highlight the trailing whitespace. Is that something we care about, or a reversed "|", "/" and "\" are already too ugly that we won't want to support them?

graph.c static void graph_output_pre_commit_line(struct git_graph *graph, · line 720

Quoted 10 lines
graph.c +4 -1
@@ -648,8 +713,11 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
 	for (i = 0; i < graph->num_columns; i++) {
 		struct column *col = &graph->columns[i];
 		if (col->commit == graph->commit) {
+			struct strbuf tmp = STRBUF_INIT;
 			seen_this = 1;
-			strbuf_addf(sb, "| %*s", graph->expansion_row, "");
+			strbuf_addf(&tmp, "| %*s", graph->expansion_row, "");
+			strbuf_write_column(sb, col, tmp.buf);
+			strbuf_release(&tmp);

Same here.

Quoted 7 lines
graph.c +1 -1
@@ -662,13 +730,13 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
 			 */
 			if (graph->prev_state == GRAPH_POST_MERGE &&
 			    graph->prev_commit_index < i)
-				strbuf_addstr(sb, "\\ ");
+				strbuf_write_column(sb, col, "\\ ");
 			else

graph.c static void graph_output_pre_commit_line(struct git_graph *graph, · line 741

Quoted 10 lines
graph.c +3 -3
-				strbuf_addstr(sb, "| ");
+				strbuf_write_column(sb, col, "| ");
 		} else if (seen_this && (graph->expansion_row > 0)) {
-			strbuf_addstr(sb, "\\ ");
+			strbuf_write_column(sb, col, "\\ ");
 		} else {
-			strbuf_addstr(sb, "| ");
+			strbuf_write_column(sb, col, "| ");
 		}
 	}

Likewise.

Quoted 13 lines
graph.c +7 -1
@@ -744,14 +813,25 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
 			if (graph->num_parents < 3)
 				strbuf_addch(sb, ' ');
 			else {
+				/*
+				 * Here dashless_commits represents the
+				 * number of parents which don't need
+				 * to have dashes (because their edges
+				 * fit neatly under the commit).
+				 */
+				const int dashless_commits = 2;
 				int num_dashes =
-					((graph->num_parents - 2) * 2) - 1;

graph.c static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) · line 831

Quoted 10 lines
graph.c +7 -2
+					((graph->num_parents - dashless_commits) * 2) - 1;
 				for (j = 0; j < num_dashes; j++)
-					strbuf_addch(sb, '-');
-				strbuf_addstr(sb, ". ");
+					strbuf_write_column(sb,
+							    &graph->new_columns[(j / 2) + dashless_commits],
+							    "-");
+				strbuf_write_column(sb,
+						    &graph->new_columns[(j / 2) + dashless_commits],
+						    ". ");

The nesting seems to be becoming too deep and the body of the for loop is getting too long. Time to make it a helper function that handles only one column, perhaps?

#3 lore raw
Quoted 12 lines · Junio C Hamano

graph.c struct column { · line 74

Quoted 9 lines · Allan Caffee
graph.c +2 -2
@@ -72,11 +69,21 @@ struct column {
 	 */
 	struct commit *commit;
 	/*
-	 * XXX: Once we add support for colors, struct column could also
-	 * contain the color of its branch line.
+	 * The color to (optionally) print this column in.
 	 */
+	const char *color;
Quoted 7 lines

You already use short for git_graph.default_column_color and I suspect in the longer term you want to make this one an index into column_colors[] array the same way. We may someday decide to support non-ANSI color scheme using ncurses or something, and at that point the "hardware color" constants like GIT_COLOR_RED and friends may change from strings to small integers we use to call our (yet to be written) curses interface layer with.

The problem with making it an index into the column_colors array is that we don't have a convenient place to test whether the user actually wants color. We can't do it in strbuf_write_column because AFAIK there's no way to get the rev-info to test the options. I suppose we could define GIT_NOT_A_COLOR to -1 and just set the color to that when we don't intend to use color. (Either way I should probably change that to an unsigned short.) What do you think?

Quoted 8 lines

graph.c static struct commit_list *first_interesting_parent(struct git_graph *graph) · line 346

Quoted 5 lines
graph.c +1 -0
@@ -312,6 +343,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph)
 	return next_interesting_parent(graph, parents);
 }
 
+static const char* graph_get_current_column_color(const struct git_graph* graph)

Style. Asterisk comes next to identifiers, not types (the parameter to graph_increment_column_color has the same issue).

Okay.

Quoted 13 lines

static const char *graph_...color(const struct git_graph *graph)

graph.c static void graph_output_padding_line(struct git_graph *graph, · line 664

Quoted 6 lines
graph.c +1 -1
@@ -596,7 +661,7 @@ static void graph_output_padding_line(struct git_graph *graph,
 	 * Output a padding row, that leaves all branch lines unchanged
 	 */
 	for (i = 0; i < graph->num_new_columns; i++) {
-		strbuf_addstr(sb, "| ");
+		strbuf_write_column(sb, &graph->new_columns[i], "| ");

Hmmm, this forbids us to use reverse color in the color palette because that would highlight the trailing whitespace. Is that something we care about, or a reversed "|", "/" and "\" are already too ugly that we won't want to support them?

Personally I don't think it's a good idea to limit the colors just because they would "look funny". It seems to me that if the user wanted the background colored they would expect to see just the line segment colored and not the whitespace.

The simplest way to fix this AFAIKS is to change strbuf_write_column to take a single character and change the existing code to add spaces in seperately.

/* For example */
strbuf_write_column(sb, &graph->new_columns[i], "| "); /* Becomes */
strbuf_write_column(sb, &graph->new_columns[i], '|'); strbuf_addch(sb, ' ');

This would fix the problem at the minor expense of adding ~15 lines of code.

Quoted 21 lines

[...]

Quoted 19 lines
graph.c +10 -3
@@ -744,14 +813,25 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
 			if (graph->num_parents < 3)
 				strbuf_addch(sb, ' ');
 			else {
+				/*
+				 * Here dashless_commits represents the
+				 * number of parents which don't need
+				 * to have dashes (because their edges
+				 * fit neatly under the commit).
+				 */
+				const int dashless_commits = 2;
 				int num_dashes =
-					((graph->num_parents - 2) * 2) - 1;
+					((graph->num_parents - dashless_commits) * 2) - 1;
 				for (j = 0; j < num_dashes; j++)
-					strbuf_addch(sb, '-');
-				strbuf_addstr(sb, ". ");
+					strbuf_write_column(sb,
+							    &graph->new_columns[(j / 2) + dashless_commits],
Quoted 8 lines

graph.c static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) · line 831

Quoted 4 lines
graph.c +4 -0
+							    "-");
+				strbuf_write_column(sb,
+						    &graph->new_columns[(j / 2) + dashless_commits],
+						    ". ");

The nesting seems to be becoming too deep and the body of the for loop is getting too long. Time to make it a helper function that handles only one column, perhaps?

If I understand this correctly in order to write a per column function would be like:

/*
* Draw one peice of the commit line and return the new value of
* seen_this.
*/
static int graph_commit_line_draw_column(struct git_graph *graph,
struct strbuf *sb, int i, int seen_this)

Which moves the entire body of the for loop into a function and only reduces the indentation by one level. Am I missing something?

#4 lore raw
Quoted 7 lines · Allan Caffee

The problem with making it an index into the column_colors array is that we don't have a convenient place to test whether the user actually wants color. We can't do it in strbuf_write_column because AFAIK there's no way to get the rev-info to test the options. I suppose we could define GIT_NOT_A_COLOR to -1 and just set the color to that when we don't intend to use color. (Either way I should probably change that to an unsigned short.) What do you think?

Sounds sensible.

#5 lore raw

PATCH v3 1/1 graph API: Added logic for colored edges

Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk.

---

Here's a list of the changes this round (I can send individual patches if it's easier to review):

* graph API: Fix graph_pad_horizontal to work properly with colors The horizontal padding was counting the number of characters in the
strbuf in order to decide how much whitespace to pad the row with. The ANSI escape sequences for colors and attributes are not printable characters but do contribute to the length of the strbuf. This fix teaches strbuf's to count printing characters (i.e. characters that consume space).
* graph.c: Add graph_draw_octopus_merge() to simplify graph_output_commit_line()
* --graph: Fix whitespace discoloration
Background colors now work as expected (but boy are they ugly ;).
* graph.c: Store colors as unsigned short
* graph: Fixed up some stylistic issues with pointers

~Allan

 color.h  |    1 +
 graph.c  |  212 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 strbuf.c |   39 +++++++++++
 strbuf.h |    1 +
 4 files changed, 211 insertions(+), 42 deletions(-)
color.h +1 -0
index 6846be1..18abeb7 100644
@@ -11,6 +11,7 @@
 #define GIT_COLOR_GREEN		"\033[32m"
 #define GIT_COLOR_YELLOW	"\033[33m"
 #define GIT_COLOR_BLUE		"\033[34m"
+#define GIT_COLOR_MAGENTA	"\033[35m"
 #define GIT_COLOR_CYAN		"\033[36m"
 #define GIT_COLOR_BG_RED	"\033[41m"
 
graph.c +170 -42

371 lines not on this page · raw message

strbuf.c +39 -0
index a884960..f525d51 100644
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include "cache.h"
 #include "refs.h"
 
@@ -138,6 +139,44 @@ void strbuf_list_free(struct strbuf **sbs)
 	free(sbs);
 }
 
+/*
+ * Return the length of the escape sequence in a string buffer
+ * starting at index i.  If there is no escape sequence starting at
+ * return 0.
+ */
+inline size_t strbuf_esc_sequence_length(const struct strbuf *sb, size_t i)
+{
+	size_t start = i;
+	if (sb->buf[i] != '\033')
+		return 0;
+	++i;
+
+	if (i >= sb->len || sb->buf[i] != '[')
+		return 0;
+	++i;
+	while (i < sb->len && isdigit(sb->buf[i]))
+		++i;
+
+	if (i >= sb->len || sb->buf[i] != 'm')
+		return 0;
+	return i - start;
+}
+
+size_t strbuf_count_printing_chars(const struct strbuf *sb)
+{
+	int i;
+	size_t n = 0;
+	size_t esc_len;
+	for (i = 0; i < sb->len; i++) {
+		esc_len = strbuf_esc_sequence_length(sb, i);
+		if (esc_len)
+			i += esc_len;
+		else if (isgraph(sb->buf[i]) || sb->buf[i] == ' ')
+			++n;
+	}
+	return n;
+}
+
 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 {
 	int len = a->len < b->len ? a->len: b->len;
strbuf.h +1 -0
index 9ee908a..3851ddf 100644
@@ -86,6 +86,7 @@ extern void strbuf_tolower(struct strbuf *);
 extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
 extern void strbuf_list_free(struct strbuf **);
 
+extern size_t strbuf_count_printing_chars(const struct strbuf *sb);
 /*----- add data in your buffer -----*/
 static inline void strbuf_addch(struct strbuf *sb, int c) {
 	strbuf_grow(sb, 1);
Signature · 1 line
1.5.6.3
#6 lore raw
Quoted 14 lines · Allan Caffee
graph.c +1 -0
index 162a516..beb622a 100644
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "commit.h"
+#include "color.h"
 #include "graph.h"
 #include "diff.h"
 #include "revision.h"
@@ -72,11 +69,14 @@ struct column {
 	 */
 	struct commit *commit;

graph.c struct column { · line 78

Quoted 10 lines
graph.c +4 -2
 	/*
-	 * XXX: Once we add support for colors, struct column could also
-	 * contain the color of its branch line.
+	 * The color to (optionally) print this column in.  This is an
+	 * index into column_colors.
 	 */
+	unsigned short color;
 };
 
+const unsigned short GIT_NOT_A_COLOR = -1;

That (-1) is an unusual value for an *unsigned* short variable.

Quoted 9 lines
graph.c +5 -0
@@ -714,10 +790,30 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
 	strbuf_addch(sb, '*');
 }
 
+inline void graph_draw_octopus_merge(const struct git_graph *graph,
+				     struct strbuf *sb)
+{
+	/*
+	 * Here dashless_commits represents the number of parents

graph.c static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) · line 807

Quoted 10 lines
graph.c +10 -0
+	 * which don't need to have dashes (because their edges fit
+	 * neatly under the commit).
+	 */
+	const int dashless_commits = 2;
+	int col_num, i;
+	int num_dashes =
+		((graph->num_parents - dashless_commits) * 2) - 1;
+	for (i = 0; i < num_dashes; i++) {
+		col_num = (i / 2) + dashless_commits;
+		strbuf_write_column(sb, &graph->new_columns[col_num], '-');

graph.c: In function 'graph_draw_octopus_merge':
graph.c:807: error: 'strbuf_write_column' is static but used in inline function 'graph_draw_octopus_merge' which is not static graph.c:810: error: 'strbuf_write_column' is static but used in inline function 'graph_draw_octopus_merge' which is not static
make: *** [graph.o] Error 1

In general, I'd prefer people not to say "inline" unless (1) they know what they are doing, and (2) the code is really performance critical.

At least I do not think the colored commit graph is performance critical, especially a function that only deals with octopus merges.

#7 lore raw
Quoted 25 lines · Junio C Hamano
Quoted 23 lines · Allan Caffee
graph.c +4 -2
index 162a516..beb622a 100644
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "commit.h"
+#include "color.h"
 #include "graph.h"
 #include "diff.h"
 #include "revision.h"
@@ -72,11 +69,14 @@ struct column {
 	 */
 	struct commit *commit;
 	/*
-	 * XXX: Once we add support for colors, struct column could also
-	 * contain the color of its branch line.
+	 * The color to (optionally) print this column in.  This is an
+	 * index into column_colors.
 	 */
+	unsigned short color;
 };
 
Quoted 3 lines

graph.c struct column { · line 78

Quoted 1 line
graph.c +1 -0
+const unsigned short GIT_NOT_A_COLOR = -1;

That (-1) is an unusual value for an *unsigned* short variable.

Perhaps you would prefer USHRT_MAX? I noticed that none of the existing code #includes limits.h. Is it safe to assume this header is present?

Quoted 25 lines
Quoted 9 lines
graph.c +5 -0
@@ -714,10 +790,30 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
 	strbuf_addch(sb, '*');
 }
 
+inline void graph_draw_octopus_merge(const struct git_graph *graph,
+				     struct strbuf *sb)
+{
+	/*
+	 * Here dashless_commits represents the number of parents

graph.c static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) · line 807

Quoted 10 lines
graph.c +10 -0
+	 * which don't need to have dashes (because their edges fit
+	 * neatly under the commit).
+	 */
+	const int dashless_commits = 2;
+	int col_num, i;
+	int num_dashes =
+		((graph->num_parents - dashless_commits) * 2) - 1;
+	for (i = 0; i < num_dashes; i++) {
+		col_num = (i / 2) + dashless_commits;
+		strbuf_write_column(sb, &graph->new_columns[col_num], '-');

graph.c: In function 'graph_draw_octopus_merge':
graph.c:807: error: 'strbuf_write_column' is static but used in inline function 'graph_draw_octopus_merge' which is not static graph.c:810: error: 'strbuf_write_column' is static but used in inline function 'graph_draw_octopus_merge' which is not static
make: *** [graph.o] Error 1

Quoted 5 lines

In general, I'd prefer people not to say "inline" unless (1) they know what they are doing, and (2) the code is really performance critical.

At least I do not think the colored commit graph is performance critical, especially a function that only deals with octopus merges.

Okay. I'll remove the inline specifier from all the functions I added.

#8 lore raw
Quoted 6 lines · Allan Caffee
Quoted 3 lines
Quoted 1 line

+const unsigned short GIT_NOT_A_COLOR = -1;

That (-1) is an unusual value for an *unsigned* short variable.

Perhaps you would prefer USHRT_MAX? I noticed that none of the existing code #includes limits.h. Is it safe to assume this header is present?

I expected to see something like

	#define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors)+1)

	write_with_color(...) {
                if (c->color < COLUMN_COLORS_MAX)
                        add color prefix;
                add string
                if (c->color < COLUMN_COLORS_MAX)
                        add color suffix;
	}

instead, actually, and was a bit surprised with (-1).

#9 lore raw

PATCH v4 1/1 graph API: Added logic for colored edges

Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk.

---

Quoted 23 lines · Junio C Hamano
Quoted 8 lines · Allan Caffee
Quoted 3 lines
Quoted 1 line

+const unsigned short GIT_NOT_A_COLOR = -1;

That (-1) is an unusual value for an *unsigned* short variable.

Perhaps you would prefer USHRT_MAX? I noticed that none of the existing
code #includes limits.h. Is it safe to assume this header is present?

I expected to see something like

      #define COLUMN_COLORS_MAX (ARRAY_SIZE(column_colors)+1)

      write_with_color(...) {
                if (c->color < COLUMN_COLORS_MAX)
                        add color prefix;
                add string
                if (c->color < COLUMN_COLORS_MAX)
                        add color suffix;
      }
Quoted 1 line

instead, actually, and was a bit surprised with (-1).

Junio,

I assumed that the +1 in your example was a typo since AFAIKS ARRAY_SIZE should give us one past the last index. If that's not correct let me know and I'll fix it.

Also if git is to be expanded allow the use of non-ANSI color codes (or already does so) the strbuf_escape_sequence_length needs to be updated to accept the relevant escape codes.

Thanks for all the help,
Allan

 color.h  |    1 +
 graph.c  |  212 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 strbuf.c |   39 +++++++++++
 strbuf.h |    1 +
 4 files changed, 211 insertions(+), 42 deletions(-)
color.h +1 -0
index 6846be1..18abeb7 100644
@@ -11,6 +11,7 @@
 #define GIT_COLOR_GREEN		"\033[32m"
 #define GIT_COLOR_YELLOW	"\033[33m"
 #define GIT_COLOR_BLUE		"\033[34m"
+#define GIT_COLOR_MAGENTA	"\033[35m"
 #define GIT_COLOR_CYAN		"\033[36m"
 #define GIT_COLOR_BG_RED	"\033[41m"
 
graph.c +170 -42

371 lines not on this page · raw message

strbuf.c +39 -0
index a884960..666460d 100644
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include "cache.h"
 #include "refs.h"
 
@@ -138,6 +139,44 @@ void strbuf_list_free(struct strbuf **sbs)
 	free(sbs);
 }
 
+/*
+ * Return the length of the escape sequence in a string buffer
+ * starting at index i.  If there is no escape sequence starting at
+ * return 0.
+ */
+size_t strbuf_esc_sequence_length(const struct strbuf *sb, size_t i)
+{
+	size_t start = i;
+	if (sb->buf[i] != '\033')
+		return 0;
+	++i;
+
+	if (i >= sb->len || sb->buf[i] != '[')
+		return 0;
+	++i;
+	while (i < sb->len && isdigit(sb->buf[i]))
+		++i;
+
+	if (i >= sb->len || sb->buf[i] != 'm')
+		return 0;
+	return i - start;
+}
+
+size_t strbuf_count_printing_chars(const struct strbuf *sb)
+{
+	int i;
+	size_t n = 0;
+	size_t esc_len;
+	for (i = 0; i < sb->len; i++) {
+		esc_len = strbuf_esc_sequence_length(sb, i);
+		if (esc_len)
+			i += esc_len;
+		else if (isgraph(sb->buf[i]) || sb->buf[i] == ' ')
+			++n;
+	}
+	return n;
+}
+
 int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 {
 	int len = a->len < b->len ? a->len: b->len;
strbuf.h +1 -0
index 9ee908a..3851ddf 100644
@@ -86,6 +86,7 @@ extern void strbuf_tolower(struct strbuf *);
 extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
 extern void strbuf_list_free(struct strbuf **);
 
+extern size_t strbuf_count_printing_chars(const struct strbuf *sb);
 /*----- add data in your buffer -----*/
 static inline void strbuf_addch(struct strbuf *sb, int c) {
 	strbuf_grow(sb, 1);
Signature · 1 line
1.5.6.3
#10 lore raw
Quoted 2 lines · Allan Caffee

I assumed that the +1 in your example was a typo since AFAIKS ARRAY_SIZE should give us one past the last index.

You are correct.

Quoted 3 lines

Also if git is to be expanded allow the use of non-ANSI color codes (or already does so) the strbuf_escape_sequence_length needs to be updated to accept the relevant escape codes.

Actually, I am starting to hate this.

Just step back a bit and imagine how you would do this, if you _were_ writing an application to do this kind of thing, generating output directly to the terminal. You obviously would not seek back and count the width of what you sent out. Instead,...?

That's right. You just keep a running total of how much you sent, iow, what column you expect the current cursor should be. Can't we do the same thing here?

graph.c static struct commit_list *first_interesting_parent(struct git_graph *graph) · line 354

Quoted 5 lines
graph.c +1 -0
@@ -312,6 +351,33 @@ static struct commit_list *first_interesting_parent(struct git_graph *graph)
 	return next_interesting_parent(graph, parents);
 }
 
+unsigned short graph_get_current_column_color(const struct git_graph *graph)

static?

graph.c static struct commit_list *first_interesting_parent(struct git_graph *graph) · line 367

Quoted 4 lines
graph.c +4 -0
+static void graph_increment_column_color(struct git_graph *graph)
+{
+	graph->default_column_color = (graph->default_column_color + 1) %
+		ARRAY_SIZE(column_colors);

COLUMN_COLORS_MAX?

graph.c static struct commit_list *first_interesting_parent(struct git_graph *graph) · line 372

Quoted 3 lines
graph.c +3 -0
+unsigned short graph_find_commit_color(const struct git_graph *graph,
+				       const struct commit *commit)
+{

static?

graph.c static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb) · line 794

Quoted 6 lines
graph.c +2 -0
@@ -714,10 +790,30 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
 	strbuf_addch(sb, '*');
 }
 
+void graph_draw_octopus_merge(const struct git_graph *graph,
+			      struct strbuf *sb)

static?

graph.c static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb) · line 885

Quoted 7 lines
graph.c +3 -0
@@ -789,6 +880,17 @@ static void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
 		graph_update_state(graph, GRAPH_COLLAPSING);
 }
 
+struct column *find_new_column_by_commit(struct git_graph *graph,
+					 struct commit *commit)
+{

static?

strbuf.c line 3

Quoted 8 lines
strbuf.c +1 -0
index a884960..666460d 100644
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include "cache.h"
 #include "refs.h"

BAD. Do not directly include system headers. If you need isgraph(), please support it as part of sane_ctype. But if you count what you emitted so far, you would not have to do this at all.

Quoted 9 lines
strbuf.c +9 -0
+/*
+ * Return the length of the escape sequence in a string buffer
+ * starting at index i.  If there is no escape sequence starting at
+ * return 0.
+ */
+size_t strbuf_esc_sequence_length(const struct strbuf *sb, size_t i)
+{
+	size_t start = i;
+	if (sb->buf[i] != '\033')

strbuf.c void strbuf_list_free(struct strbuf **sbs) · line 161

Quoted 10 lines
strbuf.c +10 -0
+		return 0;
+	++i;
+
+	if (i >= sb->len || sb->buf[i] != '[')
+		return 0;
+	++i;
+	while (i < sb->len && isdigit(sb->buf[i]))
+		++i;
+	if (i >= sb->len || sb->buf[i] != 'm')
+		return 0;

These preincrements are extremely unreadable at least for me.

	if (sb->buf[i++] != '\033')
        	return 0;
	if (sb->len <= i || sb->buf[i++] != '[')
        	return 0;
	...

But again the point is hopefully moot.

#11 lore raw

PATCH v5 1/1 graph API: Added logic for colored edges

Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk.

---
 color.h |    1 +
 graph.c |  246 ++++++++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 199 insertions(+), 48 deletions(-)
color.h +1 -0
index 6846be1..18abeb7 100644
@@ -11,6 +11,7 @@
 #define GIT_COLOR_GREEN		"\033[32m"
 #define GIT_COLOR_YELLOW	"\033[33m"
 #define GIT_COLOR_BLUE		"\033[34m"
+#define GIT_COLOR_MAGENTA	"\033[35m"
 #define GIT_COLOR_CYAN		"\033[36m"
 #define GIT_COLOR_BG_RED	"\033[41m"
 
graph.c +198 -48

445 lines not on this page · raw message

Signature · 1 line
1.5.6.3
#12 lore raw
In reply to Allan Caffee
Quoted 2 lines · Allan Caffee

Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk.

I like the colored graph very much, thanks. Unfortunately there are some problems with aligning of log messages and headers. For example, try this in git.git repository:

$ git log -1 --graph 796b137

* commit 796b13781aecce551b8f92049a66646e60f31dce

|\ Merge: 6da14ee db12d97
| | Author: Junio C Hamano <[email protected]>
| | Date:   2009-04-08 23:41:27 -0700

Without colors or without your patch the alignment is correct:

$ git log -1 --graph --no-color 796b137

* commit 796b13781aecce551b8f92049a66646e60f31dce

|\  Merge: 6da14ee db12d97
| | Author: Junio C Hamano <[email protected]>
| | Date:   2009-04-08 23:41:27 -0700

(Perhaps the "Merge:" header could have two spaces befor the data, but this is unrelated to --graph.)

#13 lore raw
Quoted 22 lines · Teemu Likonen
Quoted 2 lines · Allan Caffee

Modified the graph drawing logic to colorize edges based on parent-child relationships similiarly to gitk.

I like the colored graph very much, thanks. Unfortunately there are some problems with aligning of log messages and headers. For example, try this in git.git repository:

$ git log -1 --graph 796b137

* commit 796b13781aecce551b8f92049a66646e60f31dce

|\ Merge: 6da14ee db12d97
| | Author: Junio C Hamano <[email protected]>
| | Date:   2009-04-08 23:41:27 -0700

Without colors or without your patch the alignment is correct:

$ git log -1 --graph --no-color 796b137
Quoted 8 lines

* commit 796b13781aecce551b8f92049a66646e60f31dce

|\  Merge: 6da14ee db12d97
| | Author: Junio C Hamano <[email protected]>
| | Date:   2009-04-08 23:41:27 -0700

(Perhaps the "Merge:" header could have two spaces befor the data, but this is unrelated to --graph.)

Thanks for the feedback! The problem here is that graph_horizontal_padding was counting the number of characters in the strbuf in order to decide how much whitespace to pad the row with. The ANSI escape sequences for colors and attributes are not printable characters but do contribute to the length of the strbuf. This can be fixed by adding a new function that counts only printing characters/spaces. I'll include this in my next round.