git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH/RFC] blame: accept multiple -L ranges
@ 2013-07-07  8:45 Eric Sunshine
  2013-07-07  9:58 ` Junio C Hamano
  0 siblings, 1 reply; 22+ messages in thread
From: Eric Sunshine @ 2013-07-07  8:45 UTC (permalink / raw)
  To: git; +Cc: Eric Sunshine

git-blame accepts only zero or one -L option. Clients requiring blame
information for multiple disjoint ranges are therefore forced either to
invoke git-blame multiple times, once for each range, or only once with
no -L option to cover the entire file, which can be costly. Teach
git-blame to accept multiple -L ranges.

Overlapping and out-of-order ranges are accepted and handled gracefully.
For example:

  git blame -L 3,+4 -L 91,+7 -L 2,3 -L 89,100 source.c

emits blame information for lines 2-6 and 89-100.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---

This is RFC because it lacks documentation and test updates, and because
I want to make sure the approach is sound and not abusive of the blame
machinery.

Rather than sorting and coalescing input -L ranges manually, existing
add_blame_range() and coalesce() are (ab)used to normalize the input.
This requires a small change to coalesce() to deal with potentially
overlapping ranges since it never otherwise encounters overlap during
normal blame operation.

This patch is somewhat less scary when whitespace changes are ignored.


 builtin/blame.c | 70 +++++++++++++++++++++++++++++----------------------------
 1 file changed, 36 insertions(+), 34 deletions(-)

diff --git a/builtin/blame.c b/builtin/blame.c
index 079dcd3..f26ff44 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -278,8 +278,11 @@ static void coalesce(struct scoreboard *sb)
 	for (ent = sb->ent; ent && (next = ent->next); ent = next) {
 		if (same_suspect(ent->suspect, next->suspect) &&
 		    ent->guilty == next->guilty &&
-		    ent->s_lno + ent->num_lines == next->s_lno) {
-			ent->num_lines += next->num_lines;
+		    ent->s_lno + ent->num_lines >= next->s_lno) {
+			int ent_top = ent->lno + ent->num_lines;
+			int next_top = next->lno + next->num_lines;
+			if (ent_top < next_top)
+				ent->num_lines = next_top - ent->s_lno;
 			ent->next = next->next;
 			if (ent->next)
 				ent->next->prev = ent;
@@ -2245,17 +2248,6 @@ static int blame_move_callback(const struct option *option, const char *arg, int
 	return 0;
 }
 
-static int blame_bottomtop_callback(const struct option *option, const char *arg, int unset)
-{
-	const char **bottomtop = option->value;
-	if (!arg)
-		return -1;
-	if (*bottomtop)
-		die("More than one '-L n,m' option given");
-	*bottomtop = arg;
-	return 0;
-}
-
 int cmd_blame(int argc, const char **argv, const char *prefix)
 {
 	struct rev_info revs;
@@ -2263,11 +2255,11 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 	struct scoreboard sb;
 	struct origin *o;
 	struct blame_entry *ent;
-	long dashdash_pos, bottom, top, lno;
+	long dashdash_pos, lno;
 	const char *final_commit_name = NULL;
 	enum object_type type;
 
-	static const char *bottomtop = NULL;
+	static struct string_list ranges;
 	static int output_option = 0, opt = 0;
 	static int show_stats = 0;
 	static const char *revs_file = NULL;
@@ -2293,13 +2285,14 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 		OPT_STRING(0, "contents", &contents_from, N_("file"), N_("Use <file>'s contents as the final image")),
 		{ OPTION_CALLBACK, 'C', NULL, &opt, N_("score"), N_("Find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback },
 		{ OPTION_CALLBACK, 'M', NULL, &opt, N_("score"), N_("Find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback },
-		OPT_CALLBACK('L', NULL, &bottomtop, N_("n,m"), N_("Process only line range n,m, counting from 1"), blame_bottomtop_callback),
+		OPT_STRING_LIST('L', NULL, &ranges, N_("n,m"), N_("Process only line range n,m, counting from 1")),
 		OPT__ABBREV(&abbrev),
 		OPT_END()
 	};
 
 	struct parse_opt_ctx_t ctx;
 	int cmd_is_annotate = !strcmp(argv[0], "annotate");
+	unsigned int range_i;
 
 	git_config(git_blame_config, NULL);
 	init_revisions(&revs, NULL);
@@ -2492,24 +2485,33 @@ parse_done:
 	num_read_blob++;
 	lno = prepare_lines(&sb);
 
-	bottom = top = 0;
-	if (bottomtop)
-		prepare_blame_range(&sb, bottomtop, lno, &bottom, &top);
-	if (bottom < 1)
-		bottom = 1;
-	if (top < 1)
-		top = lno;
-	bottom--;
-	if (lno < top || lno < bottom)
-		die("file %s has only %lu lines", path, lno);
-
-	ent = xcalloc(1, sizeof(*ent));
-	ent->lno = bottom;
-	ent->num_lines = top - bottom;
-	ent->suspect = o;
-	ent->s_lno = bottom;
-
-	sb.ent = ent;
+	if (!ranges.nr)
+		string_list_append(&ranges, xstrdup("0,0"));
+
+	for (range_i = 0; range_i < ranges.nr; ++range_i) {
+		long bottom, top;
+		prepare_blame_range(&sb, ranges.items[range_i].string,
+				    lno, &bottom, &top);
+		if (bottom < 1)
+			bottom = 1;
+		if (top < 1)
+			top = lno;
+		bottom--;
+		if (lno < top || lno < bottom)
+			die("file %s has only %lu lines", path, lno);
+
+		ent = xcalloc(1, sizeof(*ent));
+		ent->lno = bottom;
+		ent->num_lines = top - bottom;
+		ent->suspect = o;
+		ent->s_lno = bottom;
+		add_blame_entry(&sb, ent);
+	}
+	coalesce(&sb);
+
+	origin_decref(o);
+	string_list_clear(&ranges, 0);
+
 	sb.path = path;
 
 	read_mailmap(&mailmap, NULL);
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2013-07-22 21:34 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-07  8:45 [PATCH/RFC] blame: accept multiple -L ranges Eric Sunshine
2013-07-07  9:58 ` Junio C Hamano
2013-07-09 15:04   ` Eric Sunshine
2013-07-09 16:39     ` Junio C Hamano
2013-07-09 17:17       ` Eric Sunshine
2013-07-09 17:42       ` Thomas Rast
2013-07-09 18:23         ` Eric Sunshine
2013-07-09 18:55           ` Junio C Hamano
2013-07-09 19:07             ` Eric Sunshine
2013-07-09 19:12             ` Thomas Rast
2013-07-09 19:21               ` Jonathan Nieder
2013-07-09 19:31               ` Junio C Hamano
2013-07-09 19:57                 ` Michael Haggerty
2013-07-09 20:25                   ` Junio C Hamano
2013-07-22  8:12                     ` Eric Sunshine
2013-07-22 10:39                       ` Thomas Rast
2013-07-22 17:23                         ` Junio C Hamano
2013-07-22 19:19                           ` Thomas Rast
2013-07-22 21:34                             ` Junio C Hamano
2013-07-10  9:18                 ` Thomas Rast
2013-07-11 16:44                   ` Junio C Hamano
2013-07-09 18:57         ` Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).