From 91b5494e18965e51c924ca55aaa27e94ebd82dd2 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Aug 2013 09:59:39 -0400 Subject: t8001/t8002: blame: add tests of multiple -L options Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 't') diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index ce5b8ed304..77083d9dde 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -271,6 +271,38 @@ test_expect_success 'blame -L ,Y (Y > nlines)' ' test_must_fail $PROG -L,12345 file ' +test_expect_success 'blame -L multiple (disjoint)' ' + check_count -L2,3 -L6,7 A 1 B1 1 B2 1 "A U Thor" 1 +' + +test_expect_success 'blame -L multiple (disjoint: unordered)' ' + check_count -L6,7 -L2,3 A 1 B1 1 B2 1 "A U Thor" 1 +' + +test_expect_success 'blame -L multiple (adjacent)' ' + check_count -L2,3 -L4,5 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (adjacent: unordered)' ' + check_count -L4,5 -L2,3 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (overlapping)' ' + check_count -L2,4 -L3,5 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (overlapping: unordered)' ' + check_count -L3,5 -L2,4 A 1 B 1 B2 1 D 1 +' + +test_expect_success 'blame -L multiple (superset/subset)' ' + check_count -L2,8 -L3,5 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L multiple (superset/subset: unordered)' ' + check_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + test_expect_success 'setup -L :regex' ' tr Q "\\t" >hello.c <<-\EOF && int main(int argc, const char *argv[]) -- cgit v1.3-5-g9baa From 52f4d1264854485bfd50afeeed1933a3f9e05c96 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Aug 2013 09:59:42 -0400 Subject: blame: teach -L/RE/ to search from end of previous -L range Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- builtin/blame.c | 5 ++++- t/annotate-tests.sh | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 't') diff --git a/builtin/blame.c b/builtin/blame.c index 7b084d8445..1bf8056f6b 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2280,6 +2280,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) int cmd_is_annotate = !strcmp(argv[0], "annotate"); struct range_set ranges; unsigned int range_i; + long anchor; git_config(git_blame_config, NULL); init_revisions(&revs, NULL); @@ -2475,11 +2476,12 @@ parse_done: if (lno && !range_list.nr) string_list_append(&range_list, xstrdup("1")); + anchor = 1; range_set_init(&ranges, range_list.nr); for (range_i = 0; range_i < range_list.nr; ++range_i) { long bottom, top; if (parse_range_arg(range_list.items[range_i].string, - nth_line_cb, &sb, lno, 1, + nth_line_cb, &sb, lno, anchor, &bottom, &top, sb.path)) usage(blame_usage); if (lno < top || ((lno || bottom) && lno < bottom)) @@ -2490,6 +2492,7 @@ parse_done: top = lno; bottom--; range_set_append_unsafe(&ranges, bottom, top); + anchor = top + 1; } sort_and_merge_range_set(&ranges); diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 77083d9dde..b963d36325 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -303,6 +303,26 @@ test_expect_success 'blame -L multiple (superset/subset: unordered)' ' check_count -L3,5 -L2,8 A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 ' +test_expect_success 'blame -L /RE/ (relative)' ' + check_count -L3,3 -L/fox/ B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/ (relative: no preceding range)' ' + check_count -L/dog/ A 1 B 1 B1 1 B2 1 C 1 D 1 "A U Thor" 1 +' + +test_expect_success 'blame -L /RE/ (relative: adjacent)' ' + check_count -L1,1 -L/dog/,+1 A 1 E 1 +' + +test_expect_success 'blame -L /RE/ (relative: not found)' ' + test_must_fail $PROG -L4,4 -L/dog/ file +' + +test_expect_success 'blame -L /RE/ (relative: end-of-file)' ' + test_must_fail $PROG -L, -L/$/ file +' + test_expect_success 'setup -L :regex' ' tr Q "\\t" >hello.c <<-\EOF && int main(int argc, const char *argv[]) -- cgit v1.3-5-g9baa From a6ac5f9864958f65269d8d58a049324403b039fd Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Aug 2013 09:59:45 -0400 Subject: line-range: teach -L^/RE/ to search from start of file The -L/RE/ option of blame/log searches from the end of the previous -L range, if any. Add new notation -L^/RE/ to override this behavior and search from start of file. The new ^/RE/ syntax is valid only as the argument of -L,. The argument, as usual, is relative to . Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/line-range-format.txt | 1 + line-range.c | 10 ++++++++-- t/annotate-tests.sh | 21 +++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) (limited to 't') diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt index 42d74f75ad..cf84417060 100644 --- a/Documentation/line-range-format.txt +++ b/Documentation/line-range-format.txt @@ -11,6 +11,7 @@ absolute line number (lines count from 1). This form will use the first line matching the given POSIX regex. If is a regex, it will search from the end of the previous `-L` range, if any, otherwise from the start of file. +If is ``^/regex/'', it will search from the start of file. If is a regex, it will search starting at the line given by . + diff --git a/line-range.c b/line-range.c index bbf3c0f448..70484899ac 100644 --- a/line-range.c +++ b/line-range.c @@ -59,8 +59,14 @@ static const char *parse_loc(const char *spec, nth_line_fn_t nth_line, return term; } - if (begin < 0) - begin = -begin; + if (begin < 0) { + if (spec[0] != '^') + begin = -begin; + else { + begin = 1; + spec++; + } + } if (spec[0] != '/') return spec; diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index b963d36325..5a7d7c72d1 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -323,6 +323,23 @@ test_expect_success 'blame -L /RE/ (relative: end-of-file)' ' test_must_fail $PROG -L, -L/$/ file ' +test_expect_success 'blame -L ^/RE/ (absolute)' ' + check_count -L3,3 -L^/dog/,+2 A 1 B2 1 +' + +test_expect_success 'blame -L ^/RE/ (absolute: no preceding range)' ' + check_count -L^/dog/,+2 A 1 B2 1 +' + +test_expect_success 'blame -L ^/RE/ (absolute: not found)' ' + test_must_fail $PROG -L4,4 -L^/tambourine/ file +' + +test_expect_success 'blame -L ^/RE/ (absolute: end-of-file)' ' + n=$(expr $(wc -l hello.c <<-\EOF && int main(int argc, const char *argv[]) @@ -464,3 +481,7 @@ test_expect_success 'blame -L X,+N (non-numeric N)' ' test_expect_success 'blame -L X,-N (non-numeric N)' ' test_must_fail $PROG -L1,-N file ' + +test_expect_success 'blame -L ,^/RE/' ' + test_must_fail $PROG -L1,^/99/ file +' -- cgit v1.3-5-g9baa From 1ce761a524e34f2d629759cb57c67d13acbe4a7a Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Aug 2013 09:59:46 -0400 Subject: line-range: teach -L:RE to search from end of previous -L range For consistency with -L/RE/, teach -L:RE to search relative to the end of the previous -L range, if any. The new behavior invalidates one test in t4211 which assumes that -L:RE begins searching at start of file. This test will be resurrected in a follow-up patch which teaches -L:RE how to override the default relative search behavior. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/line-range-format.txt | 3 ++- line-range.c | 12 +++++++----- t/annotate-tests.sh | 16 ++++++++++++++++ t/t4211-line-log.sh | 1 - 4 files changed, 25 insertions(+), 7 deletions(-) (limited to 't') diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt index cf84417060..469d80b242 100644 --- a/Documentation/line-range-format.txt +++ b/Documentation/line-range-format.txt @@ -24,4 +24,5 @@ of lines before or after the line given by . + If ``:'' is given in place of and , it denotes the range from the first funcname line that matches , up to the next -funcname line. +funcname line. ``:'' searches from the end of the previous `-L` range, +if any, otherwise from the start of file. diff --git a/line-range.c b/line-range.c index 70484899ac..4bae4bff21 100644 --- a/line-range.c +++ b/line-range.c @@ -161,7 +161,7 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char } static const char *parse_range_funcname(const char *arg, nth_line_fn_t nth_line_cb, - void *cb_data, long lines, long *begin, long *end, + void *cb_data, long lines, long anchor, long *begin, long *end, const char *path) { char *pattern; @@ -187,7 +187,8 @@ static const char *parse_range_funcname(const char *arg, nth_line_fn_t nth_line_ pattern = xstrndup(arg+1, term-(arg+1)); - start = nth_line_cb(cb_data, 0); + anchor--; /* input is in human terms */ + start = nth_line_cb(cb_data, anchor); drv = userdiff_find_by_path(path); if (drv && drv->funcname.pattern) { @@ -205,7 +206,8 @@ static const char *parse_range_funcname(const char *arg, nth_line_fn_t nth_line_ p = find_funcname_matching_regexp(xecfg, (char*) start, ®exp); if (!p) - die("-L parameter '%s': no match", pattern); + die("-L parameter '%s' starting at line %ld: no match", + pattern, anchor + 1); *begin = 0; while (p > nth_line_cb(cb_data, *begin)) (*begin)++; @@ -244,7 +246,7 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, anchor = lines + 1; if (*arg == ':') { - arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, begin, end, path); + arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, anchor, begin, end, path); if (!arg || *arg) return -1; return 0; @@ -269,7 +271,7 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, const char *skip_range_arg(const char *arg) { if (*arg == ':') - return parse_range_funcname(arg, NULL, NULL, 0, NULL, NULL, NULL); + return parse_range_funcname(arg, NULL, NULL, 0, 0, NULL, NULL, NULL); arg = parse_loc(arg, NULL, NULL, 0, -1, NULL); diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 5a7d7c72d1..4f7d6baef5 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -382,6 +382,22 @@ test_expect_success 'blame -L :nomatch' ' test_must_fail $PROG -L:nomatch hello.c ' +test_expect_success 'blame -L :RE (relative)' ' + check_count -f hello.c -L3,3 -L:ma.. F 1 H 4 +' + +test_expect_success 'blame -L :RE (relative: no preceding range)' ' + check_count -f hello.c -L:ma.. F 4 G 1 +' + +test_expect_success 'blame -L :RE (relative: not found)' ' + test_must_fail $PROG -L3,3 -L:tambourine hello.c +' + +test_expect_success 'blame -L :RE (relative: end-of-file)' ' + test_must_fail $PROG -L, -L:main hello.c +' + test_expect_success 'setup incremental' ' ( GIT_AUTHOR_NAME=I && diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh index b01b3ddebb..8ba2d511e5 100755 --- a/t/t4211-line-log.sh +++ b/t/t4211-line-log.sh @@ -48,7 +48,6 @@ canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main canned_test "-L 4,12:a.c -L :main:a.c simple" multiple -canned_test "-L 4,18:a.c -L :main:a.c simple" multiple-overlapping canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset -- cgit v1.3-5-g9baa From 215e76c7ff8be46b8206c45aed3b6ec29069d4fc Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Aug 2013 09:59:47 -0400 Subject: line-range: teach -L^:RE to search from start of file The -L:RE option of blame/log searches from the end of the previous -L range, if any. Add new notation -L^:RE to override this behavior and search from start of file. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- Documentation/line-range-format.txt | 1 + line-range.c | 9 +++++++-- t/annotate-tests.sh | 17 +++++++++++++++++ t/t4211-line-log.sh | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) (limited to 't') diff --git a/Documentation/line-range-format.txt b/Documentation/line-range-format.txt index 469d80b242..d7f26039ca 100644 --- a/Documentation/line-range-format.txt +++ b/Documentation/line-range-format.txt @@ -26,3 +26,4 @@ If ``:'' is given in place of and , it denotes the range from the first funcname line that matches , up to the next funcname line. ``:'' searches from the end of the previous `-L` range, if any, otherwise from the start of file. +``^:'' searches from the start of file. diff --git a/line-range.c b/line-range.c index 4bae4bff21..ede0c6c98f 100644 --- a/line-range.c +++ b/line-range.c @@ -173,6 +173,11 @@ static const char *parse_range_funcname(const char *arg, nth_line_fn_t nth_line_ int reg_error; regex_t regexp; + if (*arg == '^') { + anchor = 1; + arg++; + } + assert(*arg == ':'); term = arg+1; while (*term && *term != ':') { @@ -245,7 +250,7 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, if (anchor > lines) anchor = lines + 1; - if (*arg == ':') { + if (*arg == ':' || (*arg == '^' && *(arg + 1) == ':')) { arg = parse_range_funcname(arg, nth_line_cb, cb_data, lines, anchor, begin, end, path); if (!arg || *arg) return -1; @@ -270,7 +275,7 @@ int parse_range_arg(const char *arg, nth_line_fn_t nth_line_cb, const char *skip_range_arg(const char *arg) { - if (*arg == ':') + if (*arg == ':' || (*arg == '^' && *(arg + 1) == ':')) return parse_range_funcname(arg, NULL, NULL, 0, 0, NULL, NULL, NULL); arg = parse_loc(arg, NULL, NULL, 0, -1, NULL); diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 4f7d6baef5..dabe89d91a 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -398,6 +398,23 @@ test_expect_success 'blame -L :RE (relative: end-of-file)' ' test_must_fail $PROG -L, -L:main hello.c ' +test_expect_success 'blame -L ^:RE (absolute)' ' + check_count -f hello.c -L3,3 -L^:ma.. F 4 G 1 +' + +test_expect_success 'blame -L ^:RE (absolute: no preceding range)' ' + check_count -f hello.c -L^:ma.. F 4 G 1 +' + +test_expect_success 'blame -L ^:RE (absolute: not found)' ' + test_must_fail $PROG -L4,4 -L^:tambourine hello.c +' + +test_expect_success 'blame -L ^:RE (absolute: end-of-file)' ' + n=$(printf "%d" $(wc -l Date: Tue, 6 Aug 2013 09:59:48 -0400 Subject: t8001/t8002: blame: add tests of -L line numbers less than 1 git-blame -L is documented as accepting 1-based line numbers. When handed a line number less than 1, -L's behavior is undocumented and undefined; it's also nonsensical and should be rejected but is nevertheless accepted. Demonstrate this shortcoming. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- t/annotate-tests.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 't') diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index dabe89d91a..376b042f2f 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -185,6 +185,18 @@ test_expect_success 'blame -L Y,X (undocumented)' ' check_count -L6,3 B 1 B1 1 B2 1 D 1 ' +test_expect_failure 'blame -L -X' ' + test_must_fail $PROG -L-1 file +' + +test_expect_failure 'blame -L 0' ' + test_must_fail $PROG -L0 file +' + +test_expect_failure 'blame -L ,0' ' + test_must_fail $PROG -L,0 file +' + test_expect_success 'blame -L ,+0' ' test_must_fail $PROG -L,+0 file ' -- cgit v1.3-5-g9baa From 5ce922a014f78684a96c3d03a51decf0d21fa58d Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 6 Aug 2013 09:59:49 -0400 Subject: line-range: reject -L line numbers less than 1 Since inception, git-blame -L has been documented as accepting 1-based line numbers. When handed a line number less than 1, -L's behavior is undocumented and undefined; it's also nonsensical and should be diagnosed as an error. Do so. Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- line-range.c | 5 ++++- t/annotate-tests.sh | 18 +++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 't') diff --git a/line-range.c b/line-range.c index ede0c6c98f..de4e32f942 100644 --- a/line-range.c +++ b/line-range.c @@ -54,8 +54,11 @@ static const char *parse_loc(const char *spec, nth_line_fn_t nth_line, } num = strtol(spec, &term, 10); if (term != spec) { - if (ret) + if (ret) { + if (num <= 0) + die("-L invalid line number: %ld", num); *ret = num; + } return term; } diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh index 376b042f2f..99caa42f5c 100644 --- a/t/annotate-tests.sh +++ b/t/annotate-tests.sh @@ -185,15 +185,15 @@ test_expect_success 'blame -L Y,X (undocumented)' ' check_count -L6,3 B 1 B1 1 B2 1 D 1 ' -test_expect_failure 'blame -L -X' ' +test_expect_success 'blame -L -X' ' test_must_fail $PROG -L-1 file ' -test_expect_failure 'blame -L 0' ' +test_expect_success 'blame -L 0' ' test_must_fail $PROG -L0 file ' -test_expect_failure 'blame -L ,0' ' +test_expect_success 'blame -L ,0' ' test_must_fail $PROG -L,0 file ' @@ -447,8 +447,8 @@ test_expect_success 'blame empty' ' check_count -h HEAD^^ -f incremental ' -test_expect_success 'blame -L 0 empty (undocumented)' ' - check_count -h HEAD^^ -f incremental -L0 +test_expect_success 'blame -L 0 empty' ' + test_must_fail $PROG -L0 incremental HEAD^^ ' test_expect_success 'blame -L 1 empty' ' @@ -463,8 +463,8 @@ test_expect_success 'blame half' ' check_count -h HEAD^ -f incremental I 1 ' -test_expect_success 'blame -L 0 half (undocumented)' ' - check_count -h HEAD^ -f incremental -L0 I 1 +test_expect_success 'blame -L 0 half' ' + test_must_fail $PROG -L0 incremental HEAD^ ' test_expect_success 'blame -L 1 half' ' @@ -483,8 +483,8 @@ test_expect_success 'blame full' ' check_count -f incremental I 1 ' -test_expect_success 'blame -L 0 full (undocumented)' ' - check_count -f incremental -L0 I 1 +test_expect_success 'blame -L 0 full' ' + test_must_fail $PROG -L0 incremental ' test_expect_success 'blame -L 1 full' ' -- cgit v1.3-5-g9baa