Re: [PATCH v4 1/2] blame: prevent error if range ends past end of file

2018-05-01 Thread Junio C Hamano
Isabella Stephens  writes:

> This is the existing behaviour. -L10,-20 for example will blame the
> first 10 lines of a file, it will not fail. My patch doesn't change
> this. The case I am discussing is -L,-20 which at the moment blames
> the first line of the file. Trying to go backwards from the start of
> a file should be considered invalid, in my opinion, however I don't
> feel strongly about it - I don't expect this case is common in 
> practice.

I tend to think that -L,-20 is a sloppy spelling of -L1,-20
(i.e. anything omitted gets reasonable default, and for something
that specifies both ends, i.e. ",", the beginning and
the end of the file would be such reasonable default, respectively),
and as such I would imagine that the user would expect the same
behaviour as -L1,-20.  If the longhand version gives only the first
line (i.e. show up to 20 lines ending at line #1), I'd say that
sounds sensible.

Or does -L1,-20 show nothing and consider the input invalid?  If so,
then sure, -L,-20 should also be an invalid input.



Re: [PATCH v4 1/2] blame: prevent error if range ends past end of file

2018-04-26 Thread Isabella Stephens
> Maybe I misread the previous discussion and/or your cover letter,
> but I have been assuming that you are trying to avoid failing the
> command in a useless way (e.g. when the file has only ~800 lines but
> the user does not know exactly how many, instead of letting -L1,820 
> to fail with "the file only has 815 lines", pretend that the -L1,815
> was given) and instead give a reasonable fall-back behaviour.

That's correct. In doing so I picked up on a few extra cases where the
behaviour wasn't intuitive, so I've attempted to fix all of those with
this patch. 

> And to be consistent with that world view, I would have expected
> that the meaning of -L,-20 to be updated from "fail if
>  is before line #20, or show 20 lines leading to
> " to "show lines leading to , up to 20 lines
> but it is OK if there aren't enough lines in the file to show that
> many".

This is the existing behaviour. -L10,-20 for example will blame the
first 10 lines of a file, it will not fail. My patch doesn't change
this. The case I am discussing is -L,-20 which at the moment blames
the first line of the file. Trying to go backwards from the start of
a file should be considered invalid, in my opinion, however I don't
feel strongly about it - I don't expect this case is common in 
practice.


Re: [PATCH v4 1/2] blame: prevent error if range ends past end of file

2018-04-26 Thread Junio C Hamano
Isabella Stephens  writes:

> On 27/4/18 10:50 am, Junio C Hamano wrote:
>> isteph...@atlassian.com writes:
>> 
>>> diff --git a/line-range.c b/line-range.c
>>> index 323399d16..023aee1f5 100644
>>> --- a/line-range.c
>>> +++ b/line-range.c
>>> @@ -47,7 +47,7 @@ static const char *parse_loc(const char *spec, 
>>> nth_line_fn_t nth_line,
>>> else if (!num)
>>> *ret = begin;
>>> else
>>> -   *ret = begin + num;
>>> +   *ret = begin + num ? begin + num : -1;
>> 
>> When parsing "-L,-20" to grab some lines before the line
>> specified by , if that something happens to be line #20,
>> this gives -1 to *ret.  If it is line #19, *ret becomes -1, and if
>> it is line #18 or before, *ret becomes -2, -3, ...
>> 
>> Is that what we really want here?  It is disturbing that only line
>> #19 and #20 are treated identically in the above example.  If it
>> were "if going backwards by -num lines from begin goes beyond the
>> beginning of the file, clip it to the first line", I would
>> understand it, but as written, I am not sure what the code is trying
>> to do.
>> 

[administrivia] Do not top-post, but cull the context to leave
enough to remind readers what the discussion was about.

> My intention was to modify existing behaviour as little as possible,
> but I agree clipping to the first line makes a lot more sense. That
> raises the question though, do we clip to 1 and treat -L,-n as a valid
> input, or clip to -1 so that this case be detected?

Maybe I misread the previous discussion and/or your cover letter,
but I have been assuming that you are trying to avoid failing the
command in a useless way (e.g. when the file has only ~800 lines but
the user does not know exactly how many, instead of letting -L1,820 
to fail with "the file only has 815 lines", pretend that the -L1,815
was given) and instead give a reasonable fall-back behaviour.

And to be consistent with that world view, I would have expected
that the meaning of -L,-20 to be updated from "fail if
 is before line #20, or show 20 lines leading to
" to "show lines leading to , up to 20 lines
but it is OK if there aren't enough lines in the file to show that
many".

So the answer to the question probably depends on what happens when
"this case is detected" by returning -1 from here.  Do we detect and
fail?  That would defeat the overall theme of these patches.  Do we
detct and warn but continue?  That may be sensible in theory, but in
practice, especially where this "the users may not know how many
lines exactly the blob has, so do not force them to count" matters,
"blame" and "log" would show a lot of output that is sent to the
pager, so the warning message may not be shown in a noticeable way.
Compared to that, "pretend as if the first line was specified and go
on" looks like we have one fewer thing to worry about ;-)




Re: [PATCH v4 1/2] blame: prevent error if range ends past end of file

2018-04-26 Thread Isabella Stephens
My intention was to modify existing behaviour as little as possible,
but I agree clipping to the first line makes a lot more sense. That
raises the question though, do we clip to 1 and treat -L,-n as a valid
input, or clip to -1 so that this case be detected?

On 27/4/18 10:50 am, Junio C Hamano wrote:
> isteph...@atlassian.com writes:
> 
>> diff --git a/line-range.c b/line-range.c
>> index 323399d16..023aee1f5 100644
>> --- a/line-range.c
>> +++ b/line-range.c
>> @@ -47,7 +47,7 @@ static const char *parse_loc(const char *spec, 
>> nth_line_fn_t nth_line,
>>  else if (!num)
>>  *ret = begin;
>>  else
>> -*ret = begin + num;
>> +*ret = begin + num ? begin + num : -1;
> 
> When parsing "-L,-20" to grab some lines before the line
> specified by , if that something happens to be line #20,
> this gives -1 to *ret.  If it is line #19, *ret becomes -1, and if
> it is line #18 or before, *ret becomes -2, -3, ...
> 
> Is that what we really want here?  It is disturbing that only line
> #19 and #20 are treated identically in the above example.  If it
> were "if going backwards by -num lines from begin goes beyond the
> beginning of the file, clip it to the first line", I would
> understand it, but as written, I am not sure what the code is trying
> to do.
> 


Re: [PATCH v4 1/2] blame: prevent error if range ends past end of file

2018-04-26 Thread Junio C Hamano
isteph...@atlassian.com writes:

> diff --git a/line-range.c b/line-range.c
> index 323399d16..023aee1f5 100644
> --- a/line-range.c
> +++ b/line-range.c
> @@ -47,7 +47,7 @@ static const char *parse_loc(const char *spec, 
> nth_line_fn_t nth_line,
>   else if (!num)
>   *ret = begin;
>   else
> - *ret = begin + num;
> + *ret = begin + num ? begin + num : -1;

When parsing "-L,-20" to grab some lines before the line
specified by , if that something happens to be line #20,
this gives -1 to *ret.  If it is line #19, *ret becomes -1, and if
it is line #18 or before, *ret becomes -2, -3, ...

Is that what we really want here?  It is disturbing that only line
#19 and #20 are treated identically in the above example.  If it
were "if going backwards by -num lines from begin goes beyond the
beginning of the file, clip it to the first line", I would
understand it, but as written, I am not sure what the code is trying
to do.


[PATCH v4 1/2] blame: prevent error if range ends past end of file

2018-04-26 Thread istephens
From: Isabella Stephens 

If the -L option is used to specify a line range in git blame, and the
end of the range is past the end of the file, git will fail with a fatal
error. This commit prevents such behavior - instead we display the blame
for existing lines within the specified range. Tests and documentation
are ammended accordingly.

This commit also fixes two corner cases. Blaming -L n,-(n+1) now blames
the first n lines of a file rather than from n to the end of the file.
Blaming -L ,-n will complain of an empty range, rather than blaming the
whole file.

Signed-off-by: Isabella Stephens 
---
 Documentation/git-blame.txt   | 10 ++
 builtin/blame.c   |  6 --
 line-range.c  |  2 +-
 t/t8003-blame-corner-cases.sh | 17 +
 4 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 16323eb80..8cb81f57a 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -152,6 +152,16 @@ Also you can use a regular expression to specify the line 
range:
 
 which limits the annotation to the body of the `hello` subroutine.
 
+A range that begins or ends outside the bounds of the file will
+blame the relevant lines. For example:
+
+   git blame -L 10,-20 foo
+   git blame -L 10,+20 foo
+
+will respectively blame the first 10 and last 11 lines of a
+20 line file. However, blaming a line range that is entirely
+outside the bounds of the file will fail.
+
 When you are not interested in changes older than version
 v2.6.18, or changes older than 3 weeks, you can use revision
 range specifiers  similar to 'git rev-list':
diff --git a/builtin/blame.c b/builtin/blame.c
index 9dcb367b9..1204ab142 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -886,13 +886,15 @@ int cmd_blame(int argc, const char **argv, const char 
*prefix)
nth_line_cb, , lno, anchor,
, , sb.path))
usage(blame_usage);
-   if (lno < top || ((lno || bottom) && lno < bottom))
+   if (!bottom && top < 0)
+   die("-L invalid empty range");
+   if ((!lno && (top || bottom)) || lno < bottom)
die(Q_("file %s has only %lu line",
   "file %s has only %lu lines",
   lno), path, lno);
if (bottom < 1)
bottom = 1;
-   if (top < 1)
+   if (top < 1 || lno < top)
top = lno;
bottom--;
range_set_append_unsafe(, bottom, top);
diff --git a/line-range.c b/line-range.c
index 323399d16..023aee1f5 100644
--- a/line-range.c
+++ b/line-range.c
@@ -47,7 +47,7 @@ static const char *parse_loc(const char *spec, nth_line_fn_t 
nth_line,
else if (!num)
*ret = begin;
else
-   *ret = begin + num;
+   *ret = begin + num ? begin + num : -1;
return term;
}
return spec;
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
index 661f9d430..4a0c51658 100755
--- a/t/t8003-blame-corner-cases.sh
+++ b/t/t8003-blame-corner-cases.sh
@@ -216,14 +216,23 @@ test_expect_success 'blame -L with invalid start' '
 '
 
 test_expect_success 'blame -L with invalid end' '
-   test_must_fail git blame -L1,5 tres 2>errors &&
-   test_i18ngrep "has only 2 lines" errors
+   git blame -L1,5 tres >out &&
+   test_line_count = 2 out
 '
 
 test_expect_success 'blame parses  part of -L' '
git blame -L1,1 tres >out &&
-   cat out &&
-   test $(wc -l < out) -eq 1
+   test_line_count = 1 out
+'
+
+test_expect_success 'blame -Ln,-(n+1)' '
+   git blame -L3,-4 nine_lines >out &&
+   test_line_count = 3 out
+'
+
+test_expect_success 'blame -L,-n' '
+   test_must_fail git blame -L,-1 tres 2>errors &&
+   test_i18ngrep "-L invalid empty range"
 '
 
 test_expect_success 'indent of line numbers, nine lines' '
-- 
2.14.3 (Apple Git-98)