From: Bo Yang <struggleyb.nku@gmail.com>
To: git@vger.kernel.org
Cc: Jens.Lehmann@web.de, trast@student.ethz.ch, gitster@pobox.com
Subject: [PATCH V5 09/17] Print the line log
Date: Wed, 11 Aug 2010 23:03:34 +0800 [thread overview]
Message-ID: <1281539022-31616-10-git-send-email-struggleyb.nku@gmail.com> (raw)
In-Reply-To: <1281539022-31616-1-git-send-email-struggleyb.nku@gmail.com>
'struct line_chunk' is used to make sure each file is scanned
only once when printing the lines. We track the starting line
number and the offsets of all lines in the range in this struct.
We use two functions from diff.c to generate meta info and hunk
headers in the usual format.
Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>
---
line.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 238 insertions(+), 0 deletions(-)
diff --git a/line.c b/line.c
index ae52832..d50c0e8 100644
--- a/line.c
+++ b/line.c
@@ -1006,3 +1006,241 @@ static void assign_parents_range(struct rev_info *rev, struct commit *commit)
cleanup(evil);
}
+struct line_chunk {
+ int lone, ltwo;
+ const char *one, *two;
+ const char *one_end, *two_end;
+ struct diff_line_range *range;
+};
+
+static void flush_lines(struct diff_options *opt, const char **ptr, const char *end,
+ int slno, int elno, int *lno, const char *color, const char heading)
+{
+ const char *p = *ptr;
+ struct strbuf buf = STRBUF_INIT;
+ const char *reset;
+
+ if (*color)
+ reset = diff_get_color_opt(opt, DIFF_RESET);
+ else
+ reset = "";
+
+ strbuf_addf(&buf, "%s%c", color, heading);
+ while (*ptr < end && *lno < slno) {
+ if (**ptr == '\n') {
+ (*lno)++;
+ if (*lno == slno) {
+ (*ptr)++;
+ break;
+ }
+ }
+ (*ptr)++;
+ }
+ assert(*ptr <= end);
+ p = *ptr;
+
+ while (*ptr < end && *lno <= elno) {
+ if (**ptr == '\n') {
+ fprintf(opt->file, "%s", buf.buf);
+ if (*ptr - p)
+ fwrite(p, *ptr - p, 1, opt->file);
+ fprintf(opt->file, "%s\n", reset);
+ p = *ptr + 1;
+ (*lno)++;
+ }
+ (*ptr)++;
+ }
+ if (*lno <= elno) {
+ fprintf(opt->file, "%s", buf.buf);
+ if (*ptr - p)
+ fwrite(p, *ptr - p, 1, opt->file);
+ fprintf(opt->file, "%s\n", reset);
+ }
+ strbuf_release(&buf);
+}
+
+static void diff_flush_range(struct diff_options *opt, struct line_chunk *chunk,
+ struct line_range *range)
+{
+ struct print_pair *pair = &range->pair;
+ const char *old = diff_get_color_opt(opt, DIFF_FILE_OLD);
+ const char *new = diff_get_color_opt(opt, DIFF_FILE_NEW);
+ int i, cur = range->start;
+
+ for (i = 0; i < pair->nr; i++) {
+ struct print_range *pr = pair->ranges + i;
+ if (cur < pr->start)
+ flush_lines(opt, &chunk->two, chunk->two_end,
+ cur, pr->start - 1, &chunk->ltwo, "", ' ');
+
+ if (!pr->line_added)
+ flush_lines(opt, &chunk->one, chunk->one_end,
+ pr->pstart, pr->pend, &chunk->lone, old, '-');
+ flush_lines(opt, &chunk->two, chunk->two_end,
+ pr->start, pr->end, &chunk->ltwo, new, '+');
+
+ cur = pr->end + 1;
+ }
+
+ if (cur <= range->end) {
+ flush_lines(opt, &chunk->two, chunk->two_end,
+ cur, range->end, &chunk->ltwo, "", ' ');
+ }
+}
+
+static void diff_flush_chunks(struct diff_options *opt, struct line_chunk *chunk)
+{
+ struct diff_line_range *range = chunk->range;
+ const char *set = diff_get_color_opt(opt, DIFF_FRAGINFO);
+ const char *reset = diff_get_color_opt(opt, DIFF_RESET);
+ int i;
+
+ for (i = 0; i < range->nr; i++) {
+ struct line_range *r = range->ranges + i;
+ long lenp = r->pend - r->pstart + 1, pstart = r->pstart;
+ long len = r->end - r->start + 1;
+ if (pstart == 0)
+ lenp = 0;
+
+ fprintf(opt->file, "%s@@ -%ld,%ld +%ld,%ld @@%s\n",
+ set, pstart, lenp, r->start, len, reset);
+
+ diff_flush_range(opt, chunk, r);
+ }
+}
+
+static void diff_flush_filepair(struct rev_info *rev, struct diff_line_range *range)
+{
+ struct diff_options *opt = &rev->diffopt;
+ struct diff_filespec *one = range->prev, *two = range->spec;
+ struct diff_filepair p = {one, two, range->status, 0};
+ struct strbuf header = STRBUF_INIT, meta = STRBUF_INIT;
+ const char *a_prefix, *b_prefix;
+ const char *name_a, *name_b, *a_one, *b_two;
+ const char *lbl[2];
+ const char *set = diff_get_color_opt(opt, DIFF_METAINFO);
+ const char *reset = diff_get_color_opt(opt, DIFF_RESET);
+ struct line_chunk chunk;
+ int must_show_header;
+
+ /*
+ * the ranges that touch no different file, in this case
+ * the line number will not change, and of course we have
+ * no sensible rang->pair since there is no diff run.
+ */
+ if (one == NULL)
+ return;
+
+ if (range->status == DIFF_STATUS_DELETED)
+ die("We are following an nonexistent file, interesting!");
+
+ name_a = one->path;
+ name_b = two->path;
+ fill_metainfo(&meta, name_a, name_b, one, two, opt, &p, &must_show_header,
+ DIFF_OPT_TST(opt, COLOR_DIFF));
+
+ diff_set_mnemonic_prefix(opt, "a/", "b/");
+ if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
+ a_prefix = opt->b_prefix;
+ b_prefix = opt->a_prefix;
+ } else {
+ a_prefix = opt->a_prefix;
+ b_prefix = opt->b_prefix;
+ }
+
+ name_a = DIFF_FILE_VALID(one) ? name_a : name_b;
+ name_b = DIFF_FILE_VALID(two) ? name_b : name_a;
+
+ a_one = quote_two(a_prefix, name_a + (*name_a == '/'));
+ b_two = quote_two(b_prefix, name_b + (*name_b == '/'));
+ lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null";
+ lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null";
+ strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset);
+ if (lbl[0][0] == '/') {
+ strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset);
+ } else if (lbl[1][0] == '/') {
+ strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
+ } else if (one->mode != two->mode) {
+ strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset);
+ strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset);
+ }
+
+ fprintf(opt->file, "%s%s", header.buf, meta.buf);
+ strbuf_release(&meta);
+ strbuf_release(&header);
+ fprintf(opt->file, "%s--- %s%s\n", set, lbl[0], reset);
+ fprintf(opt->file, "%s+++ %s%s\n", set, lbl[1], reset);
+ free((void *)a_one);
+ free((void *)b_two);
+
+ chunk.one = one->data;
+ chunk.one_end = one->data + one->size;
+ chunk.lone = 1;
+ chunk.two = two->data;
+ chunk.two_end = two->data + two->size;
+ chunk.ltwo = 1;
+ chunk.range = range;
+ diff_flush_chunks(&rev->diffopt, &chunk);
+}
+
+#define EVIL_MERGE_STR "nontrivial merge found"
+static void flush_nontrivial_merge(struct rev_info *rev, struct diff_line_range *range)
+{
+ struct diff_options *opt = &rev->diffopt;
+ const char *reset = diff_get_color_opt(opt, DIFF_RESET);
+ const char *frag = diff_get_color_opt(opt, DIFF_FRAGINFO);
+ const char *meta = diff_get_color_opt(opt, DIFF_METAINFO);
+ const char *new = diff_get_color_opt(opt, DIFF_FILE_NEW);
+
+ fprintf(opt->file, "%s%s%s\n", meta, EVIL_MERGE_STR, reset);
+
+ while (range) {
+ if (range->nr) {
+ int lno = 1;
+ const char *ptr = range->spec->data;
+ const char *end = range->spec->data + range->spec->size;
+ int i = 0;
+ fprintf(opt->file, "%s%s%s\n\n", meta, range->spec->path, reset);
+ for (; i < range->nr; i++) {
+ struct line_range *r = range->ranges + i;
+ fprintf(opt->file, "%s@@ %ld,%ld @@%s\n", frag, r->start,
+ r->end - r->start + 1, reset);
+ flush_lines(opt, &ptr, end, r->start, r->end,
+ &lno, new, ' ');
+ }
+ fprintf(opt->file, "\n");
+ }
+ range = range->next;
+ }
+}
+
+static void line_log_flush(struct rev_info *rev, struct commit *c)
+{
+ struct diff_line_range *range = lookup_line_range(rev, c);
+ struct diff_line_range *nontrivial = lookup_decoration(&rev->nontrivial_merge, &c->object);
+ struct log_info log;
+
+ if (range == NULL)
+ return;
+
+ log.commit = c;
+ log.parent = NULL;
+ rev->loginfo = &log;
+ show_log(rev);
+ rev->loginfo = NULL;
+ /*
+ * Add a new line after each commit message, of course we should
+ * add --graph alignment later when the patches comes to master.
+ */
+ fprintf(rev->diffopt.file, "\n");
+
+ if (c->object.flags & EVIL_MERGE)
+ return flush_nontrivial_merge(rev, nontrivial);
+
+ while (range) {
+ if (range->diff)
+ diff_flush_filepair(rev, range);
+ range = range->next;
+ }
+}
+
--
1.7.2.19.g79e5d
next prev parent reply other threads:[~2010-08-11 15:05 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-11 15:03 [PATCH V5 00/17] Reroll a version 5 of this series Bo Yang
2010-08-11 15:03 ` [PATCH V5 01/17] parse-options: enhance STOP_AT_NON_OPTION Bo Yang
2010-08-11 15:03 ` [PATCH V5 02/17] parse-options: add two helper functions Bo Yang
2010-08-11 15:03 ` [PATCH V5 03/17] Add the basic data structure for line level history Bo Yang
2010-08-11 15:03 ` [PATCH V5 04/17] Refactor parse_loc Bo Yang
2010-08-11 15:03 ` [PATCH V5 05/17] Parse the -L options Bo Yang
2010-08-11 15:03 ` [PATCH V5 06/17] Export three functions from diff.c Bo Yang
2010-08-11 15:03 ` [PATCH V5 07/17] Add range clone functions Bo Yang
2010-08-11 15:03 ` [PATCH V5 08/17] map/take range to the parent of commits Bo Yang
2010-08-11 15:03 ` Bo Yang [this message]
2010-08-11 15:03 ` [PATCH V5 10/17] Hook line history into cmd_log, ensuring a topo-ordered walk Bo Yang
2010-08-11 15:03 ` [PATCH V5 11/17] Make rewrite_parents public to other part of git Bo Yang
2010-08-11 15:03 ` [PATCH V5 12/17] Make graph_next_line external " Bo Yang
2010-08-11 15:03 ` [PATCH V5 13/17] Add parent rewriting to line history browser Bo Yang
2010-08-30 17:10 ` log -L crash (Re: [PATCH V5 13/17] Add parent rewriting to line history browser) Jonathan Nieder
2010-09-01 14:47 ` Bo Yang
2010-09-11 21:10 ` [PATCH] log -L: do not free parents lists we might need again Thomas Rast
2010-08-11 15:03 ` [PATCH V5 14/17] Add --graph prefix before line history output Bo Yang
2010-08-11 15:03 ` [PATCH V5 15/17] Add --full-line-diff option Bo Yang
2010-08-11 15:03 ` [PATCH V5 16/17] Add tests for line history browser Bo Yang
2010-08-12 1:25 ` Ævar Arnfjörð Bjarmason
2010-08-12 12:24 ` Bo Yang
2010-08-12 16:27 ` Ævar Arnfjörð Bjarmason
2010-08-12 20:37 ` Junio C Hamano
2010-08-12 21:06 ` Junio C Hamano
2010-08-11 15:03 ` [PATCH V5 17/17] Document " Bo Yang
2010-08-12 8:31 ` [PATCH V5 00/17] Reroll a version 5 of this series david
2010-08-12 17:23 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1281539022-31616-10-git-send-email-struggleyb.nku@gmail.com \
--to=struggleyb.nku@gmail.com \
--cc=Jens.Lehmann@web.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=trast@student.ethz.ch \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).