From: Bo Yang <struggleyb.nku@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com
Subject: [PATCH v3 09/13] print the line log
Date: Sun, 11 Jul 2010 14:18:57 +0800 [thread overview]
Message-ID: <1278829141-11900-9-git-send-email-struggleyb.nku@gmail.com> (raw)
In-Reply-To: <1278829141-11900-1-git-send-email-struggleyb.nku@gmail.com>
'struct line_chunk' is used to make sure each file is scaned
only once when printing the lines. We trace the line number and
the start position of intermediate line in this struct.
Two helper functions from diff.c are used to generate the
consistent format of diff meta info.
Signed-off-by: Bo Yang <struggleyb.nku@gmail.com>
---
line.c | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 245 insertions(+), 0 deletions(-)
diff --git a/line.c b/line.c
index e1af2f6..8813376 100644
--- a/line.c
+++ b/line.c
@@ -951,3 +951,248 @@ static void assign_parents_range(struct rev_info *rev, struct commit *commit)
}
}
+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 (strcmp(color, ""))
+ reset = "";
+ else
+ reset = diff_get_color_opt(opt, DIFF_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;
+
+ /*
+ * todo: when --graph landed on master, this should be changed
+ * a little.
+ */
+ 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 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 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) {
+ fprintf(opt->file, "%s%s%s\n\n", meta, range->spec->path, reset);
+ int lno = 1;
+ const char *ptr = range->spec->data;
+ const char *end = range->spec->data + range->spec->size;
+ int i = 0;
+ for (; i < range->nr; i++) {
+ struct 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.0.2.273.gc2413.dirty
next prev parent reply other threads:[~2010-07-11 6:21 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-11 6:18 [PATCH v3 01/13] parse-options: stop when encounter a non-option Bo Yang
2010-07-11 6:18 ` [PATCH v3 02/13] parse-options: add two helper functions Bo Yang
2010-07-12 16:45 ` Junio C Hamano
2010-07-11 6:18 ` [PATCH v3 03/13] add the basic data structure for line level history Bo Yang
2010-07-12 14:16 ` Bo Yang
2010-07-12 16:50 ` Junio C Hamano
2010-07-18 14:35 ` Bo Yang
2010-07-11 6:18 ` [PATCH v3 04/13] refactor parse_loc Bo Yang
2010-07-12 18:32 ` Junio C Hamano
2010-07-11 6:18 ` [PATCH v3 05/13] parse the -L options Bo Yang
2010-07-13 23:03 ` Junio C Hamano
2010-07-18 14:49 ` Bo Yang
2010-07-19 18:44 ` Junio C Hamano
2010-07-19 22:48 ` Thomas Rast
2010-07-19 23:53 ` Junio C Hamano
2010-07-20 7:51 ` Thomas Rast
2010-07-20 15:45 ` Junio C Hamano
2010-07-22 9:06 ` Thomas Rast
2010-07-23 2:08 ` Junio C Hamano
2010-07-20 15:46 ` Bo Yang
2010-07-20 15:47 ` Bo Yang
2010-07-11 6:18 ` [PATCH v3 06/13] export three functions from diff.c Bo Yang
2010-07-11 6:18 ` [PATCH v3 07/13] add range clone functions Bo Yang
2010-07-12 21:52 ` Junio C Hamano
2010-07-11 6:18 ` [PATCH v3 08/13] map/take range to parent Bo Yang
2010-07-12 21:52 ` Junio C Hamano
2010-07-11 6:18 ` Bo Yang [this message]
2010-07-12 21:52 ` [PATCH v3 09/13] print the line log Junio C Hamano
2010-07-11 6:18 ` [PATCH v3 10/13] map/print ranges along traversing the history topologically Bo Yang
2010-07-12 21:52 ` Junio C Hamano
2010-07-11 6:18 ` [PATCH v3 11/13] add --always-print option Bo Yang
2010-07-13 20:35 ` Junio C Hamano
2010-07-11 6:19 ` [PATCH v3 12/13] add two test cases Bo Yang
2010-07-11 6:19 ` [PATCH v3 13/13] some document update Bo Yang
2010-07-11 8:27 ` Jakub Narebski
2010-07-12 14:12 ` Bo Yang
2010-07-12 18:45 ` Junio C Hamano
2010-07-18 14:37 ` Bo Yang
2010-07-12 16:45 ` [PATCH v3 01/13] parse-options: stop when encounter a non-option 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=1278829141-11900-9-git-send-email-struggleyb.nku@gmail.com \
--to=struggleyb.nku@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/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).