Skip to content

Commit

Permalink
graph: add support for --line-prefix on all graph-aware output
Browse files Browse the repository at this point in the history
Add an extension to git-diff and git-log (and any other graph-aware
displayable output) such that "--line-prefix=<string>" will print the
additional line-prefix on every line of output.

To make this work, we have to fix a few bugs in the graph API that force
graph_show_commit_msg to be used only when you have a valid graph.
Additionally, we extend the default_diff_output_prefix handler to work
even when no graph is enabled.

This is somewhat of a hack on top of the graph API, but I think it
should be acceptable here.

This will be used by a future extension of submodule display which
displays the submodule diff as the actual diff between the pre and post
commit in the submodule project.

Add some tests for both git-log and git-diff to ensure that the prefix
is honored correctly.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
jacob-keller authored and gitster committed Sep 1, 2016
1 parent cd48dad commit 660e113
Show file tree
Hide file tree
Showing 11 changed files with 504 additions and 80 deletions.
3 changes: 3 additions & 0 deletions Documentation/diff-options.txt
Expand Up @@ -569,5 +569,8 @@ endif::git-format-patch[]
--no-prefix::
Do not show any source or destination prefix.

--line-prefix=<prefix>::
Prepend an additional prefix to every line of output.

For more detailed explanation on these common options, see also
linkgit:gitdiffcore[7].
74 changes: 33 additions & 41 deletions builtin/rev-list.c
Expand Up @@ -122,48 +122,40 @@ static void show_commit(struct commit *commit, void *data)
ctx.fmt = revs->commit_format;
ctx.output_encoding = get_log_output_encoding();
pretty_print_commit(&ctx, commit, &buf);
if (revs->graph) {
if (buf.len) {
if (revs->commit_format != CMIT_FMT_ONELINE)
graph_show_oneline(revs->graph);

graph_show_commit_msg(revs->graph, &buf);

/*
* Add a newline after the commit message.
*
* Usually, this newline produces a blank
* padding line between entries, in which case
* we need to add graph padding on this line.
*
* However, the commit message may not end in a
* newline. In this case the newline simply
* ends the last line of the commit message,
* and we don't need any graph output. (This
* always happens with CMIT_FMT_ONELINE, and it
* happens with CMIT_FMT_USERFORMAT when the
* format doesn't explicitly end in a newline.)
*/
if (buf.len && buf.buf[buf.len - 1] == '\n')
graph_show_padding(revs->graph);
putchar('\n');
} else {
/*
* If the message buffer is empty, just show
* the rest of the graph output for this
* commit.
*/
if (graph_show_remainder(revs->graph))
putchar('\n');
if (revs->commit_format == CMIT_FMT_ONELINE)
putchar('\n');
}
if (buf.len) {
if (revs->commit_format != CMIT_FMT_ONELINE)
graph_show_oneline(revs->graph);

graph_show_commit_msg(revs->graph, stdout, &buf);

/*
* Add a newline after the commit message.
*
* Usually, this newline produces a blank
* padding line between entries, in which case
* we need to add graph padding on this line.
*
* However, the commit message may not end in a
* newline. In this case the newline simply
* ends the last line of the commit message,
* and we don't need any graph output. (This
* always happens with CMIT_FMT_ONELINE, and it
* happens with CMIT_FMT_USERFORMAT when the
* format doesn't explicitly end in a newline.)
*/
if (buf.len && buf.buf[buf.len - 1] == '\n')
graph_show_padding(revs->graph);
putchar('\n');
} else {
if (revs->commit_format != CMIT_FMT_USERFORMAT ||
buf.len) {
fwrite(buf.buf, 1, buf.len, stdout);
putchar(info->hdr_termination);
}
/*
* If the message buffer is empty, just show
* the rest of the graph output for this
* commit.
*/
if (graph_show_remainder(revs->graph))
putchar('\n');
if (revs->commit_format == CMIT_FMT_ONELINE)
putchar('\n');
}
strbuf_release(&buf);
} else {
Expand Down
7 changes: 7 additions & 0 deletions diff.c
Expand Up @@ -18,6 +18,7 @@
#include "ll-merge.h"
#include "string-list.h"
#include "argv-array.h"
#include "graph.h"

#ifdef NO_FAST_WORKING_DIRECTORY
#define FAST_WORKING_DIRECTORY 0
Expand Down Expand Up @@ -3966,6 +3967,12 @@ int diff_opt_parse(struct diff_options *options,
options->a_prefix = optarg;
return argcount;
}
else if ((argcount = parse_long_opt("line-prefix", av, &optarg))) {
options->line_prefix = optarg;
options->line_prefix_length = strlen(options->line_prefix);
graph_setup_line_prefix(options);
return argcount;
}
else if ((argcount = parse_long_opt("dst-prefix", av, &optarg))) {
options->b_prefix = optarg;
return argcount;
Expand Down
2 changes: 2 additions & 0 deletions diff.h
Expand Up @@ -115,6 +115,8 @@ struct diff_options {
const char *pickaxe;
const char *single_follow;
const char *a_prefix, *b_prefix;
const char *line_prefix;
size_t line_prefix_length;
unsigned flags;
unsigned touched_flags;

Expand Down
98 changes: 64 additions & 34 deletions graph.c
Expand Up @@ -2,7 +2,6 @@
#include "commit.h"
#include "color.h"
#include "graph.h"
#include "diff.h"
#include "revision.h"

/* Internal API */
Expand All @@ -28,8 +27,15 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb);
* responsible for printing this line's graph (perhaps via
* graph_show_commit() or graph_show_oneline()) before calling
* graph_show_strbuf().
*
* Note that unlike some other graph display functions, you must pass the file
* handle directly. It is assumed that this is the same file handle as the
* file specified by the graph diff options. This is necessary so that
* graph_show_strbuf can be called even with a NULL graph.
*/
static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb);
static void graph_show_strbuf(struct git_graph *graph,
FILE *file,
struct strbuf const *sb);

/*
* TODO:
Expand Down Expand Up @@ -59,6 +65,17 @@ enum graph_state {
GRAPH_COLLAPSING
};

static void graph_show_line_prefix(const struct diff_options *diffopt)
{
if (!diffopt || !diffopt->line_prefix)
return;

fwrite(diffopt->line_prefix,
sizeof(char),
diffopt->line_prefix_length,
diffopt->file);
}

static const char **column_colors;
static unsigned short column_colors_max;

Expand Down Expand Up @@ -195,13 +212,28 @@ static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void
static struct strbuf msgbuf = STRBUF_INIT;

assert(opt);
assert(graph);

strbuf_reset(&msgbuf);
graph_padding_line(graph, &msgbuf);
if (opt->line_prefix)
strbuf_add(&msgbuf, opt->line_prefix,
opt->line_prefix_length);
if (graph)
graph_padding_line(graph, &msgbuf);
return &msgbuf;
}

static const struct diff_options *default_diffopt;

void graph_setup_line_prefix(struct diff_options *diffopt)
{
default_diffopt = diffopt;

/* setup an output prefix callback if necessary */
if (diffopt && !diffopt->output_prefix)
diffopt->output_prefix = diff_output_prefix_callback;
}


struct git_graph *graph_init(struct rev_info *opt)
{
struct git_graph *graph = xmalloc(sizeof(struct git_graph));
Expand Down Expand Up @@ -1183,6 +1215,8 @@ void graph_show_commit(struct git_graph *graph)
struct strbuf msgbuf = STRBUF_INIT;
int shown_commit_line = 0;

graph_show_line_prefix(default_diffopt);

if (!graph)
return;

Expand All @@ -1200,8 +1234,10 @@ void graph_show_commit(struct git_graph *graph)
shown_commit_line = graph_next_line(graph, &msgbuf);
fwrite(msgbuf.buf, sizeof(char), msgbuf.len,
graph->revs->diffopt.file);
if (!shown_commit_line)
if (!shown_commit_line) {
putc('\n', graph->revs->diffopt.file);
graph_show_line_prefix(&graph->revs->diffopt);
}
strbuf_setlen(&msgbuf, 0);
}

Expand All @@ -1212,6 +1248,8 @@ void graph_show_oneline(struct git_graph *graph)
{
struct strbuf msgbuf = STRBUF_INIT;

graph_show_line_prefix(default_diffopt);

if (!graph)
return;

Expand All @@ -1224,6 +1262,8 @@ void graph_show_padding(struct git_graph *graph)
{
struct strbuf msgbuf = STRBUF_INIT;

graph_show_line_prefix(default_diffopt);

if (!graph)
return;

Expand All @@ -1237,6 +1277,8 @@ int graph_show_remainder(struct git_graph *graph)
struct strbuf msgbuf = STRBUF_INIT;
int shown = 0;

graph_show_line_prefix(default_diffopt);

if (!graph)
return 0;

Expand All @@ -1250,27 +1292,24 @@ int graph_show_remainder(struct git_graph *graph)
strbuf_setlen(&msgbuf, 0);
shown = 1;

if (!graph_is_commit_finished(graph))
if (!graph_is_commit_finished(graph)) {
putc('\n', graph->revs->diffopt.file);
else
graph_show_line_prefix(&graph->revs->diffopt);
} else {
break;
}
}
strbuf_release(&msgbuf);

return shown;
}


static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
static void graph_show_strbuf(struct git_graph *graph,
FILE *file,
struct strbuf const *sb)
{
char *p;

if (!graph) {
fwrite(sb->buf, sizeof(char), sb->len,
graph->revs->diffopt.file);
return;
}

/*
* Print the strbuf line by line,
* and display the graph info before each line but the first.
Expand All @@ -1285,37 +1324,28 @@ static void graph_show_strbuf(struct git_graph *graph, struct strbuf const *sb)
} else {
len = (sb->buf + sb->len) - p;
}
fwrite(p, sizeof(char), len, graph->revs->diffopt.file);
fwrite(p, sizeof(char), len, file);
if (next_p && *next_p != '\0')
graph_show_oneline(graph);
p = next_p;
}
}

void graph_show_commit_msg(struct git_graph *graph,
FILE *file,
struct strbuf const *sb)
{
int newline_terminated;

if (!graph) {
/*
* If there's no graph, just print the message buffer.
*
* The message buffer for CMIT_FMT_ONELINE and
* CMIT_FMT_USERFORMAT are already missing a terminating
* newline. All of the other formats should have it.
*/
fwrite(sb->buf, sizeof(char), sb->len,
graph->revs->diffopt.file);
return;
}

newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');

/*
* Show the commit message
*/
graph_show_strbuf(graph, sb);
graph_show_strbuf(graph, file, sb);

if (!graph)
return;

newline_terminated = (sb->len && sb->buf[sb->len - 1] == '\n');

/*
* If there is more output needed for this commit, show it now
Expand All @@ -1327,14 +1357,14 @@ void graph_show_commit_msg(struct git_graph *graph,
* new line.
*/
if (!newline_terminated)
putc('\n', graph->revs->diffopt.file);
putc('\n', file);

graph_show_remainder(graph);

/*
* If sb ends with a newline, our output should too.
*/
if (newline_terminated)
putc('\n', graph->revs->diffopt.file);
putc('\n', file);
}
}
22 changes: 21 additions & 1 deletion graph.h
@@ -1,9 +1,22 @@
#ifndef GRAPH_H
#define GRAPH_H
#include "diff.h"

/* A graph is a pointer to this opaque structure */
struct git_graph;

/*
* Called to setup global display of line_prefix diff option.
*
* Passed a diff_options structure which indicates the line_prefix and the
* file to output the prefix to. This is sort of a hack used so that the
* line_prefix will be honored by all flows which also honor "--graph"
* regardless of whether a graph has actually been setup. The normal graph
* flow will honor the exact diff_options passed, but a NULL graph will cause
* display of a line_prefix to stdout.
*/
void graph_setup_line_prefix(struct diff_options *diffopt);

/*
* Set up a custom scheme for column colors.
*
Expand Down Expand Up @@ -113,7 +126,14 @@ int graph_show_remainder(struct git_graph *graph);
* missing a terminating newline (including if it is empty), the output
* printed by graph_show_commit_msg() will also be missing a terminating
* newline.
*
* Note that unlike some other graph display functions, you must pass the file
* handle directly. It is assumed that this is the same file handle as the
* file specified by the graph diff options. This is necessary so that
* graph_show_commit_msg can be called even with a NULL graph.
*/
void graph_show_commit_msg(struct git_graph *graph, struct strbuf const *sb);
void graph_show_commit_msg(struct git_graph *graph,
FILE *file,
struct strbuf const *sb);

#endif /* GRAPH_H */
5 changes: 1 addition & 4 deletions log-tree.c
Expand Up @@ -715,10 +715,7 @@ void show_log(struct rev_info *opt)
else
opt->missing_newline = 0;

if (opt->graph)
graph_show_commit_msg(opt->graph, &msgbuf);
else
fwrite(msgbuf.buf, sizeof(char), msgbuf.len, opt->diffopt.file);
graph_show_commit_msg(opt->graph, opt->diffopt.file, &msgbuf);
if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) {
if (!opt->missing_newline)
graph_show_padding(opt->graph);
Expand Down

0 comments on commit 660e113

Please sign in to comment.