{"thread":{"id":"16503","subject":"summaries in git add --patch","startedAt":"2008-11-27T21:10:05Z","lastAt":"2008-12-05T02:23:49Z","messageCount":19,"participants":["William Pursell","Jakub Narebski","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"96634","messageId":"492F0CAD.3010101@gmail.com","threadId":"16503","inReplyTo":null,"subject":"summaries in git add --patch","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-11-27T21:10:05Z","receivedAt":"2008-11-27T21:10:05Z","isPatch":false,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"\nI just implemented a command to give a brief summary\nof the patches in the current file.  Please note that\nI am just rediscovering perl after having abandoned it\nyears ago, so any criticism is appreciated. 5 patches\nto follow.  (From aa14a0c3f)\n\nHere's a screen shot:\n\n\nStage this hunk [y,n,a,l,d,k,K,j,J,e,?]? l\n'*' indicates current hunk.  '+' stage, '-' don't stage\n  0+: @@ -8,9 +8,9 @@ Aani\n  1 : @@ -48,7 +48,7 @@ abandonable\n*2 : @@ -88,7 +88,7 @@ abaton\n  3 : @@ -128,7 +128,7 @@ abdest\n  4-: @@ -81192,9 +81192,9 @@ gyrous\n  5 : @@ -234925,7 +234925,7 @@ zymotic\n@@ -88,7 +88,7 @@ abaton\n  abator\n  abattoir\n  Abatua\n-abature\n+agature\n  abave\n  abaxial\n  abaxile\n\n\n\n\n-- \nWilliam Pursell\n"},{"id":"96648","messageId":"m3od00kgg9.fsf@localhost.localdomain","threadId":"16503","inReplyTo":"492F0CAD.3010101@gmail.com","subject":"Re: summaries in git add --patch","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2008-11-27T21:27:19Z","receivedAt":"2008-11-27T21:27:19Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> I just implemented a command to give a brief summary\n> of the patches in the current file.  \n\nGood idea.\n\nSide note: you should signoff your patches, following\nDocumentation/SubmittingPatches.  And it would be better\nif the patches itself were either threaded, or all be\nreplies to this cover letter ([PATCH 0/5]) email.\n\n>                                       Please note that\n> I am just rediscovering perl after having abandoned it\n> years ago, so any criticism is appreciated. 5 patches\n> to follow.  (From aa14a0c3f)\n> \n> Here's a screen shot:\n> \n> \n> Stage this hunk [y,n,a,l,d,k,K,j,J,e,?]? l\n> '*' indicates current hunk.  '+' stage, '-' don't stage\n>   0+: @@ -8,9 +8,9 @@ Aani\n>   1 : @@ -48,7 +48,7 @@ abandonable\n> *2 : @@ -88,7 +88,7 @@ abaton\n\nI hope that contrary to this 'screenshot' actual output is aligned\nproperly...\n\n>   3 : @@ -128,7 +128,7 @@ abdest\n>   4-: @@ -81192,9 +81192,9 @@ gyrous\n>   5 : @@ -234925,7 +234925,7 @@ zymotic\n\nThat of course assumes that summary catches right thing; still\nit is better than nothing.\n\n> @@ -88,7 +88,7 @@ abaton\n>   abator\n>   abattoir\n>   Abatua\n> -abature\n> +agature\n>   abave\n>   abaxial\n>   abaxile\n\nSame here.\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"96660","messageId":"7viqq8adsf.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"492F0CAD.3010101@gmail.com","subject":"Re: summaries in git add --patch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-28T00:34:56Z","receivedAt":"2008-11-28T00:34:56Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> Stage this hunk [y,n,a,l,d,k,K,j,J,e,?]? l\n> '*' indicates current hunk.  '+' stage, '-' don't stage\n>  0+: @@ -8,9 +8,9 @@ Aani\n>  1 : @@ -48,7 +48,7 @@ abandonable\n> *2 : @@ -88,7 +88,7 @@ abaton\n>  3 : @@ -128,7 +128,7 @@ abdest\n>  4-: @@ -81192,9 +81192,9 @@ gyrous\n>  5 : @@ -234925,7 +234925,7 @@ zymotic\n> @@ -88,7 +88,7 @@ abaton\n>  abator\n>  abattoir\n>  Abatua\n> -abature\n> +agature\n>  abave\n>  abaxial\n>  abaxile\n\nMachines count from zero but humans count from one.\n\nWhat is your plans to limit the output of this when there are dozens of\nhunks?\n\nA hunk can and often is quite long which would make this list scroll off\nthe screen.  Together with the previous point, I suspect it would be\nbetter to make this not part of the \"Stage this one?\" question, but an\naction that (1) does not do anything to the hunk we have currently focus\non, and (2) does not move the focus after it does its thing.  In other\nwords, a new \"status\" action.  I think 'S' is not taken yet although 's'\nis taken for 'split'.\n"},{"id":"96671","messageId":"492F754A.3080204@gmail.com","threadId":"16503","inReplyTo":"7viqq8adsf.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-11-28T04:36:26Z","receivedAt":"2008-11-28T04:36:26Z","isPatch":false,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> William Pursell <bill.pursell@gmail.com> writes:\n> \n>> Stage this hunk [y,n,a,l,d,k,K,j,J,e,?]? l\n>> '*' indicates current hunk.  '+' stage, '-' don't stage\n>>  0+: @@ -8,9 +8,9 @@ Aani\n>>  1 : @@ -48,7 +48,7 @@ abandonable\n>> *2 : @@ -88,7 +88,7 @@ abaton\n>>  3 : @@ -128,7 +128,7 @@ abdest\n>>  4-: @@ -81192,9 +81192,9 @@ gyrous\n>>  5 : @@ -234925,7 +234925,7 @@ zymotic\n>> @@ -88,7 +88,7 @@ abaton\n>>  abator\n>>  abattoir\n>>  Abatua\n>> -abature\n>> +agature\n>>  abave\n>>  abaxial\n>>  abaxile\n> \n> Machines count from zero but humans count from one.\n\nHumans should change. :)  Good point.\n\n> What is your plans to limit the output of this when there are dozens of\n> hunks?\n\nWould having git-add--interactive fork a PAGER be too drastic?\nIt strikes me as probably being unworkable, and a better\napproach would be too only display a fixed number of lines\nand not immediately display the current hunk.  (In line with\nyour suggestion below to make it a status command.)\n\n> A hunk can and often is quite long which would make this list scroll off\n> the screen.  Together with the previous point, I suspect it would be\n> better to make this not part of the \"Stage this one?\" question, but an\n> action that (1) does not do anything to the hunk we have currently focus\n> on, and (2) does not move the focus after it does its thing.  In other\n> words, a new \"status\" action.  I think 'S' is not taken yet although 's'\n> is taken for 'split'.\n\nI tend to use 'git add --patch' directly rather than\ngit add --interactive, and would prefer to be able to\naccess the list from there.  But your point is definitely\nvalid and my work flow should probably change.\n\nre: 's' vs 'S', I notice that y,n, and d are all case\ninsenstive, but the other commands are not.  Is this\nnecessary/desirable?\n\n-- \nWilliam Pursell\n"},{"id":"96675","messageId":"492F92C9.7030301@gmail.com","threadId":"16503","inReplyTo":"7viqq8adsf.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-11-28T06:42:17Z","receivedAt":"2008-11-28T06:42:17Z","isPatch":false,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"\nHere's a new patch.  Instead of displaying the summary and then\nthe current hunk, it implements a 'goto' command.  It prints the\nsummary and then prompts for the index of the hunk to jump to.\nBy not printing the current hunk, the list should typically\nstay on screen.  Also, the summary is optional, so:\n\ng  -- bring up summary and prompt for index\ng3 -- jump to hunk 3\n\n\ncommit 510edf7c28fcc571f29106e32f2570d5f2e04fc3\nAuthor: William Pursell <bill.pursell@gmail.com>\nDate:   Fri Nov 28 06:22:36 2008 +0000\n\n     Implement 'g' command (goto) in add --patch\n\n     This command prints a summary of the hunks in the current\n     file and prompts the user for an index of the hunk to make\n     current.\n\n     Signed-off-by: William Pursell <bill.pursell@gmail.com>\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex b0223c3..e6d73a0 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -553,7 +553,7 @@ sub parse_diff {\n\n  \tfor (my $i = 0; $i < @diff; $i++) {\n  \t\tif ($diff[$i] =~ /^@@ /) {\n-\t\t\tpush @hunk, { TEXT => [], DISPLAY => [] };\n+\t\t\tpush @hunk, { TEXT => [], DISPLAY => [], SUMMARY => $diff[$i] };\n  \t\t}\n  \t\tpush @{$hunk[-1]{TEXT}}, $diff[$i];\n  \t\tpush @{$hunk[-1]{DISPLAY}},\n@@ -685,6 +685,7 @@ sub split_hunk {\n  \t\t\t    (($n_cnt != 1) ? \",$n_cnt\" : '') .\n  \t\t\t    \" @@\\n\");\n  \t\tmy $display_head = $head;\n+\t\t$hunk->{SUMMARY} = $head;\n  \t\tunshift @{$hunk->{TEXT}}, $head;\n  \t\tif ($diff_use_color) {\n  \t\t\t$display_head = colored($fraginfo_color, $head);\n@@ -783,6 +784,7 @@ sub edit_hunk_loop {\n  \t\t\t\t $newhunk,\n  \t\t\t\t @{$hunk}[$ix+1..$#{$hunk}])) {\n  \t\t\t$newhunk->{DISPLAY} = [color_diff(@{$text})];\n+\t\t\t$newhunk->{SUMMARY} = $$text[0];\n  \t\t\treturn $newhunk;\n  \t\t}\n  \t\telse {\n@@ -799,6 +801,7 @@ sub help_patch_cmd {\n  y - stage this hunk\n  n - do not stage this hunk\n  a - stage this and all the remaining hunks in the file\n+g - select a hunk to jump to\n  d - do not stage this hunk nor any of the remaining hunks in the file\n  j - leave this hunk undecided, see next undecided hunk\n  J - leave this hunk undecided, see next hunk\n@@ -836,6 +839,27 @@ sub patch_update_cmd {\n  \t}\n  }\n\n+sub select_new_hunk {\n+\tmy $ri = shift;\n+\tmy @hunk = @_;\n+\tmy ($i, $response);\n+\tprint \"   '+' stage, '-' don't stage\\n\";\n+\tfor ( $i = 0; $i < @hunk; $i++ ) {\n+\t\tmy $status = \" \";\n+\t\tif( defined $hunk[$i]{USE} ) {\n+\t\t\t$status = $hunk[$i]{USE} ? \"+\" : \"-\";\n+\t\t}\n+\t\tprintf \"%s%3d: %s\",\n+\t\t\t$status,\n+\t\t\t$i + 1,\n+\t\t\t$hunk[$i]{SUMMARY};\n+\t}\n+\tprintf \"goto which hunk? \";\n+\t$response = <STDIN>;\n+\tchomp $response;\n+\t$$ri = $response - 1;\n+}\n+\n  sub patch_update_file {\n  \tmy ($ix, $num);\n  \tmy $path = shift;\n@@ -919,7 +943,7 @@ sub patch_update_file {\n  \t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n  \t\t\tprint;\n  \t\t}\n-\t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d$other/?]? \";\n+\t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d/g$other/?]? \";\n  \t\tmy $line = <STDIN>;\n  \t\tif ($line) {\n  \t\t\tif ($line =~ /^y/i) {\n@@ -937,6 +961,16 @@ sub patch_update_file {\n  \t\t\t\t}\n  \t\t\t\tnext;\n  \t\t\t}\n+\t\t\telsif ($line =~ /^g/) {\n+\t\t\t\tchomp ($line);\n+\t\t\t\tif ($line =~ /^g$/) {\n+\t\t\t\t\tselect_new_hunk (\\$ix, @hunk);\n+\t\t\t\t}\n+\t\t\t\telse {\n+\t\t\t\t\t$ix = (substr $line, 1) - 1;\n+\t\t\t\t}\n+\t\t\t\tnext;\n+\t\t\t}\n  \t\t\telsif ($line =~ /^d/i) {\n  \t\t\t\twhile ($ix < $num) {\n  \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n\n\n-- \nWilliam Pursell\n"},{"id":"96677","messageId":"7v8wr48g98.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"492F92C9.7030301@gmail.com","subject":"Re: summaries in git add --patch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-11-28T07:24:35Z","receivedAt":"2008-11-28T07:24:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> Here's a new patch.  Instead of displaying the summary and then\n> the current hunk, it implements a 'goto' command.\n\nI take it that this is for discussion not for immediate inclusion.\n\n> @@ -799,6 +801,7 @@ sub help_patch_cmd {\n>  y - stage this hunk\n>  n - do not stage this hunk\n>  a - stage this and all the remaining hunks in the file\n> +g - select a hunk to jump to\n>  d - do not stage this hunk nor any of the remaining hunks in the file\n>  j - leave this hunk undecided, see next undecided hunk\n>  J - leave this hunk undecided, see next hunk\n\nSince you took 'g' after \"go to\", help text should also say \"go to\",\ninstead of \"jump to\" for the mnemonics value, iow, to help people\nremember.\n\n> @@ -836,6 +839,27 @@ sub patch_update_cmd {\n>  \t}\n>  }\n>\n> +sub select_new_hunk {\n> +\tmy $ri = shift;\n> +\tmy @hunk = @_;\n> +\tmy ($i, $response);\n> +\tprint \"   '+' stage, '-' don't stage\\n\";\n> +\tfor ( $i = 0; $i < @hunk; $i++ ) {\n> +\t\tmy $status = \" \";\n> +\t\tif( defined $hunk[$i]{USE} ) {\n> +\t\t\t$status = $hunk[$i]{USE} ? \"+\" : \"-\";\n> +\t\t}\n\nStyle.\n\n    (1) SP between language construct and open parenthesis, as opposed to\n        no extra SP between function name and open parenthesis;\n\n    (2) No extra SP around what is enclosed in parentheses.\n\n> +\t\tprintf \"%s%3d: %s\",\n> +\t\t\t$status,\n> +\t\t\t$i + 1,\n> +\t\t\t$hunk[$i]{SUMMARY};\n> +\t}\n\nI think this \"for ()\" loop part, including the comment about +/- notation,\nshould be separated into a function so that you can implement a separate\n\"l\"ist command like you did in the other patch, using the same function.\n\n> +\tprintf \"goto which hunk? \";\n> +\t$response = <STDIN>;\n> +\tchomp $response;\n> +\t$$ri = $response - 1;\n\nWhat happens when $response is (1) a non number, (2) outside range (both\nnegative and positive), or (3) EOF?\n\nSending ref to scalar and returning the value by assigning is a bad taste.\nWhy shouldn't this function just return an integer to be assigned to $ix\nby the caller?  If you want to use pass-by-ref to show off your Perl-fu, I\nthink \\@hunk would be what you would want to for performance reasons.\n\n> @@ -919,7 +943,7 @@ sub patch_update_file {\n>  \t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n>  \t\t\tprint;\n>  \t\t}\n> -\t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d$other/?]? \";\n> +\t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d/g$other/?]? \";\n\nWhen there is only one hunk, we do not give j nor k.  Should we give g in\nsuch a case?  Why?\n\n> @@ -937,6 +961,16 @@ sub patch_update_file {\n>  \t\t\t\t}\n>  \t\t\t\tnext;\n>  \t\t\t}\n> +\t\t\telsif ($line =~ /^g/) {\n> +\t\t\t\tchomp ($line);\n> +\t\t\t\tif ($line =~ /^g$/) {\n> +\t\t\t\t\tselect_new_hunk (\\$ix, @hunk);\n> +\t\t\t\t}\n> +\t\t\t\telse {\n> +\t\t\t\t\t$ix = (substr $line, 1) - 1;\n> +\t\t\t\t}\n\nThe same \"input validation\" issue exists here.  it would make sense to:\n\n - Make choose_hunk(@hunk) that calls list_hunks(@hunk) that gives the\n   summary, reads one line, and returns that line;\n\n - Make the caller here to look like this:\n\n\telsif ($line =~ s/^g//) {\n        \tchomp($line);\n                if ($line eq '') {\n                \t$line = choose_hunk(@hunk);\n\t\t}\n\t\tif ($line !~ /^\\d+$/) {\n\t\t\tprint STDERR \"Eh '$line', what number is that?\\n\";\n                        next;\n\t\t} elsif (0 < $line && $line <= $num) {\n\t\t\t$ix = $line - 1;\n                } else {\n                \tprint STDERR \"Sorry, you have only $num hunks\\n\";\n                }\n\t}\n\n> +\t\t\t\tnext;\n> +\t\t\t}\n>  \t\t\telsif ($line =~ /^d/i) {\n>  \t\t\t\twhile ($ix < $num) {\n>  \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n>\n>\n> -- \n> William Pursell\n"},{"id":"96705","messageId":"49308B4B.3070703@gmail.com","threadId":"16503","inReplyTo":"7v8wr48g98.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-11-29T00:22:35Z","receivedAt":"2008-11-29T00:22:35Z","isPatch":false,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> William Pursell <bill.pursell@gmail.com> writes:\n> \n>> Here's a new patch.  Instead of displaying the summary and then\n>> the current hunk, it implements a 'goto' command.\n> \n> I take it that this is for discussion not for immediate inclusion.\n> \n\nYes.  I tend to think of all of my patches as being merely\nfor discussion since I'm not terribly familiar with the code\nbase and expect to miss many things.  I'm flattered that\nyou would even consider them for inclusion.  For that matter,\nI'm flattered that you have even responded to my submissions!\n\n>> @@ -799,6 +801,7 @@ sub help_patch_cmd {\n>>  y - stage this hunk\n>>  n - do not stage this hunk\n>>  a - stage this and all the remaining hunks in the file\n>> +g - select a hunk to jump to\n>>  d - do not stage this hunk nor any of the remaining hunks in the file\n>>  j - leave this hunk undecided, see next undecided hunk\n>>  J - leave this hunk undecided, see next hunk\n> \n> Since you took 'g' after \"go to\", help text should also say \"go to\",\n> instead of \"jump to\" for the mnemonics value, iow, to help people\n> remember.\n\nAgreed.\n\n>> @@ -836,6 +839,27 @@ sub patch_update_cmd {\n>>  \t}\n>>  }\n>>\n>> +sub select_new_hunk {\n>> +\tmy $ri = shift;\n>> +\tmy @hunk = @_;\n>> +\tmy ($i, $response);\n>> +\tprint \"   '+' stage, '-' don't stage\\n\";\n>> +\tfor ( $i = 0; $i < @hunk; $i++ ) {\n>> +\t\tmy $status = \" \";\n>> +\t\tif( defined $hunk[$i]{USE} ) {\n>> +\t\t\t$status = $hunk[$i]{USE} ? \"+\" : \"-\";\n>> +\t\t}\n> \n> Style.\n> \n>     (1) SP between language construct and open parenthesis, as opposed to\n>         no extra SP between function name and open parenthesis;\n> \n>     (2) No extra SP around what is enclosed in parentheses.\n\nMy apologies for that.  I do try to conform, but this\nsort of habit is hard to change.  Especially in perl,\nwhere code so often looks like a cartoon character's\nspeech bubble while swearing (eg #@$!%#@@), I\nlike to put space inside my parens.  I'm fully aware\nthat this is not the preferred style here, and I\nam trying to conform.  Is there a style validating\npre-commit hook script available?\n\n>> +\t\tprintf \"%s%3d: %s\",\n>> +\t\t\t$status,\n>> +\t\t\t$i + 1,\n>> +\t\t\t$hunk[$i]{SUMMARY};\n>> +\t}\n> \n> I think this \"for ()\" loop part, including the comment about +/- notation,\n> should be separated into a function so that you can implement a separate\n> \"l\"ist command like you did in the other patch, using the same function.\n\nMy thought is that 'g' would replace 'l', but as per your previous\nemail 'l' would be a reasonable status command, so it\nmakes sense to factor it out.\n> \n>> +\tprintf \"goto which hunk? \";\n>> +\t$response = <STDIN>;\n>> +\tchomp $response;\n>> +\t$$ri = $response - 1;\n> \n> What happens when $response is (1) a non number, (2) outside range (both\n> negative and positive), or (3) EOF?\n> \n> Sending ref to scalar and returning the value by assigning is a bad taste.\n> Why shouldn't this function just return an integer to be assigned to $ix\n> by the caller?  If you want to use pass-by-ref to show off your Perl-fu, I\n> think \\@hunk would be what you would want to for performance reasons.\n\nAck.  I have no Perl-fu, I'm just not familiar with the\nidioms and thought this was accepted in perl.  I agree\nthat it's poor judgement, and can only attribute my\nusage of it here to laziness. ( At one point I was passing\n$ix, and when I realized I wanted to modify it at the caller\nit was just easier to pass by reference.)\n\n> \n>> @@ -919,7 +943,7 @@ sub patch_update_file {\n>>  \t\tfor (@{$hunk[$ix]{DISPLAY}}) {\n>>  \t\t\tprint;\n>>  \t\t}\n>> -\t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d$other/?]? \";\n>> +\t\tprint colored $prompt_color, \"Stage this hunk [y/n/a/d/g$other/?]? \";\n> \n> When there is only one hunk, we do not give j nor k.  Should we give g in\n> such a case?  Why?\n\nI would agree that g should be invalid when only one hunk is\navailable.  I hadn't considered that case.\n\n> \n>> @@ -937,6 +961,16 @@ sub patch_update_file {\n>>  \t\t\t\t}\n>>  \t\t\t\tnext;\n>>  \t\t\t}\n>> +\t\t\telsif ($line =~ /^g/) {\n>> +\t\t\t\tchomp ($line);\n>> +\t\t\t\tif ($line =~ /^g$/) {\n>> +\t\t\t\t\tselect_new_hunk (\\$ix, @hunk);\n>> +\t\t\t\t}\n>> +\t\t\t\telse {\n>> +\t\t\t\t\t$ix = (substr $line, 1) - 1;\n>> +\t\t\t\t}\n> \n> The same \"input validation\" issue exists here.  it would make sense to:\n> \n>  - Make choose_hunk(@hunk) that calls list_hunks(@hunk) that gives the\n>    summary, reads one line, and returns that line;\n> \n>  - Make the caller here to look like this:\n> \n> \telsif ($line =~ s/^g//) {\n>         \tchomp($line);\n>                 if ($line eq '') {\n>                 \t$line = choose_hunk(@hunk);\n> \t\t}\n> \t\tif ($line !~ /^\\d+$/) {\n> \t\t\tprint STDERR \"Eh '$line', what number is that?\\n\";\n>                         next;\n> \t\t} elsif (0 < $line && $line <= $num) {\n> \t\t\t$ix = $line - 1;\n>                 } else {\n>                 \tprint STDERR \"Sorry, you have only $num hunks\\n\";\n>                 }\n> \t}\n> \n>> +\t\t\t\tnext;\n>> +\t\t\t}\n>>  \t\t\telsif ($line =~ /^d/i) {\n>>  \t\t\t\twhile ($ix < $num) {\n>>  \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n\n\nI will try to incorporate your ideas into a workable,\nincludable patch.  I think the '/' regex search can\nbecome part of the choose_hunk() routine so that\nan integer response means select by number while\na '/re' response means jump forward to next matching\nhunk.  Also, instead of storing the summary line in\nthe hunk, it will probably be better to generate on\nthe fly during the display routine.\n\nThanks for the feedback.\n\n-- \nWilliam Pursell\n"},{"id":"97005","messageId":"7vskp6j95x.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"49308B4B.3070703@gmail.com","subject":"Re: summaries in git add --patch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-03T02:15:54Z","receivedAt":"2008-12-03T02:15:54Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>> William Pursell <bill.pursell@gmail.com> writes:\n>>\n>>> Here's a new patch.  Instead of displaying the summary and then\n>>> the current hunk, it implements a 'goto' command.\n>>\n>> I take it that this is for discussion not for immediate inclusion.\n>\n> Yes.  I tend to think of all of my patches as being merely\n> for discussion since I'm not terribly familiar with the code\n> base and expect to miss many things.  I'm flattered that\n> you would even consider them for inclusion.  For that matter,\n> I'm flattered that you have even responded to my submissions!\n\nThanks.  I value contributions from people who are enthused and can make a\ngood case for the change they propose.  I utter comments and sometimes\neven send out an alternative implementation to illustrate what might be a\nbetter approach.  IOW, I try to help people make progress.\n\nOne thing I will not do after such a discussion, unless I am really really\ninterested in having the new feature personally myself, is to go back to\nthe discussion thread and assemble the pieces together to make the final\nseries of patches for inclusion.  The responsibility for doing that lies\non the original contributor.\n"},{"id":"97091","messageId":"4936EE63.209@gmail.com","threadId":"16503","inReplyTo":"7vskp6j95x.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch[PATCH 1/2]","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-12-03T20:38:59Z","receivedAt":"2008-12-03T20:38:59Z","isPatch":true,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"Junio C Hamano wrote:\n\n> One thing I will not do after such a discussion, unless I am really really\n> interested in having the new feature personally myself, is to go back to\n> the discussion thread and assemble the pieces together to make the final\n> series of patches for inclusion.  The responsibility for doing that lies\n> on the original contributor.\n> \n\nThat is a perfectly reasonable policy, and I did not intend\nto suggest that you should do that work.  My apologies if\nit seemed that way.  Here is the first of 2 patches to\nimplement the 'g' command.  I believe it is complete, but\nI am not much for user interface.  It works for me, but it\ncould be improved upon.  (For example, I took your suggestion\nand disallowed 'g' when there is only one hunk, but the\nbehavior feels clunky, although it is similar to an invalid\nk/j entry.)\n\n From de169b0062ae21f085d1309b4dd7da369029ae7d Mon Sep 17 00:00:00 2001\nFrom: William Pursell <bill.pursell@gmail.com>\nDate: Wed, 3 Dec 2008 20:25:31 +0000\nSubject: [PATCH 1/2] Add subroutine to display one-line summary of hunks.\n\nThis commit implements a rather simple-minded mechanism\nto display a one-line summary of the hunks in an array ref.\nThe display consists of the line numbers and the first\nchanged line, truncated to 80 characters.  20 lines are\ndisplayed at a time, and the index of the first undisplayed\nline is returned, allowing the caller to display more if\ndesired.  (The 20 and 80 should be made configurable.)\n\nSigned-off-by: William Pursell <bill.pursell@gmail.com>\n---\n  git-add--interactive.perl |   39 +++++++++++++++++++++++++++++++++++++++\n  1 files changed, 39 insertions(+), 0 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex b0223c3..daf8d5d 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -836,6 +836,45 @@ sub patch_update_cmd {\n  \t}\n  }\n\n+# Generate a one line summary of a hunk.\n+sub summarize_hunk {\n+\tmy $rhunk = shift;\n+\tmy $summary = $rhunk->{TEXT}[0];\n+\n+\t# Keep the line numbers, discard extra context.\n+\t$summary =~ s/(@@.*@@).*/$1 /s;\n+\n+\t# Add some user context. (Just take first changed line.)\n+\tfor my $line (@{$rhunk->{TEXT}}) {\n+\t\tif ($line =~ m/^[+-]/) {\n+\t\t\t$summary .= $line;\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\treturn substr ($summary, 0, 80);\n+}\n+\n+\n+# Print a one-line summary of each hunk in the array ref in\n+# the first argument, starting wih the index in the 2nd.\n+sub display_hunks {\n+\tmy ($hunks, $i) = @_;\n+\tmy $ctr = 0;\n+\t$i = 0 if not $i;\n+\tfor (; $i < @$hunks && $ctr < 20; $i++, $ctr++) {\n+\t\tmy $status = \" \";\n+\t\tif (defined $hunks->[$i]{USE}) {\n+\t\t\t$status = $hunks->[$i]{USE} ? \"+\" : \"-\";\n+\t\t}\n+\t\tprintf \"%s%2d: %s\",\n+\t\t\t$status,\n+\t\t\t$i + 1,\n+\t\t\tsummarize_hunk ($hunks->[$i]);\n+\t}\n+\treturn $i;\n+}\n+\n  sub patch_update_file {\n  \tmy ($ix, $num);\n  \tmy $path = shift;\n-- \n1.6.1.rc1.37.g83daf.dirty\n\n\n\n-- \nWilliam Pursell\n"},{"id":"97090","messageId":"4936EE68.6030009@gmail.com","threadId":"16503","inReplyTo":"7vskp6j95x.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch[PATCH 2/2]","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-12-03T20:39:04Z","receivedAt":"2008-12-03T20:39:04Z","isPatch":true,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"\n From 57b5eab3f64a40ebe9aca122b5c6db1ab5c26116 Mon Sep 17 00:00:00 2001\nFrom: William Pursell <bill.pursell@gmail.com>\nDate: Wed, 3 Dec 2008 20:26:36 +0000\nSubject: [PATCH 2/2] Implemented 'g' command to goto a hunk.\n\nWhen a minor change is made while the working directory\nis in a bit of a mess (and the user should have done a\nstash before making the minor edit, but didn't) it is\nsomewhat difficult to wade through all of the hunks using\ngit add --patch.  This allows one to jump to the hunk\nthat needs to be staged without having to respond 'n' to\neach preceding hunk.\n\nSigned-off-by: William Pursell <bill.pursell@gmail.com>\n---\n  git-add--interactive.perl |   25 +++++++++++++++++++++++++\n  1 files changed, 25 insertions(+), 0 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex daf8d5d..98ce8e3 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -800,6 +800,7 @@ y - stage this hunk\n  n - do not stage this hunk\n  a - stage this and all the remaining hunks in the file\n  d - do not stage this hunk nor any of the remaining hunks in the file\n+g - select a hunk to goto\n  j - leave this hunk undecided, see next undecided hunk\n  J - leave this hunk undecided, see next hunk\n  k - leave this hunk undecided, see previous undecided hunk\n@@ -943,6 +944,9 @@ sub patch_update_file {\n  \t\tif ($ix < $num - 1) {\n  \t\t\t$other .= '/J';\n  \t\t}\n+\t\tif ($num > 1) {\n+\t\t\t$other .= '/g';\n+\t\t}\n  \t\tfor ($i = 0; $i < $num; $i++) {\n  \t\t\tif (!defined $hunk[$i]{USE}) {\n  \t\t\t\t$undecided = 1;\n@@ -976,6 +980,27 @@ sub patch_update_file {\n  \t\t\t\t}\n  \t\t\t\tnext;\n  \t\t\t}\n+\t\t\telsif ($other =~ 'g' && $line =~ /^g(.*)/) {\n+\t\t\t\tmy $response = $1;\n+\t\t\t\tmy $i = 0;\n+\t\t\t\tchomp $response;\n+\t\t\t\twhile (not $response) {\n+\t\t\t\t\tmy $extra = \"\";\n+\t\t\t\t\t$i = display_hunks (\\@hunk, $i);\n+\t\t\t\t\t$extra = \"(<ret> to see more): \" if ($i != $num);\n+\t\t\t\t\tprint \"goto which hunk? $extra\";\n+\t\t\t\t\t$response = <STDIN>;\n+\t\t\t\t\tchomp $response;\n+\t\t\t\t}\n+\t\t\t\tif ($response !~ /^\\s*\\d+$/) {\n+\t\t\t\t\tprint STDERR \"Invalid number: '$response'\\n\";\n+\t\t\t\t} elsif (0 < $response && $response <= $num) {\n+\t\t\t\t\t$ix = $response - 1;\n+\t\t\t\t} else {\n+\t\t\t\t\tprint STDERR \"Sorry, only $num hunks available.\\n\";\n+\t\t\t\t}\n+\t\t\t\tnext;\n+\t\t\t}\n  \t\t\telsif ($line =~ /^d/i) {\n  \t\t\t\twhile ($ix < $num) {\n  \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n-- \n1.6.1.rc1.37.g83daf.dirty\n\n\n\n-- \nWilliam Pursell\n"},{"id":"97112","messageId":"7vd4g8alp7.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"4936EE63.209@gmail.com","subject":"Re: summaries in git add --patch[PATCH 1/2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-03T23:22:12Z","receivedAt":"2008-12-03T23:22:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>\n>> One thing I will not do after such a discussion, unless I am really really\n>> interested in having the new feature personally myself, is to go back to\n>> the discussion thread and assemble the pieces together to make the final\n>> series of patches for inclusion.  The responsibility for doing that lies\n>> on the original contributor.\n>>\n>\n> That is a perfectly reasonable policy, and I did not intend\n> to suggest that you should do that work.\n\nHeh, that is not a policy but just the way I work (rather, \"the way I\ndon't work and push the work to others instead\") with a limited amount of\ntime.\n\n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index b0223c3..daf8d5d 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -836,6 +836,45 @@ sub patch_update_cmd {\n>  \t}\n>  }\n>\n> +# Generate a one line summary of a hunk.\n> +sub summarize_hunk {\n> +\tmy $rhunk = shift;\n> +\tmy $summary = $rhunk->{TEXT}[0];\n> +\n> +\t# Keep the line numbers, discard extra context.\n> +\t$summary =~ s/(@@.*@@).*/$1 /s;\n\nYou would need to make the first glob less eager, i.e. /(@@.*?@@).*/,\notherwise you will be folled by a literal @@ in the contents that is\ntacked after \"@@ -j,k +l,m @@\".\n\nDo you really want the surrounding @@ in the result, by the way?\n\n> +\t# Add some user context. (Just take first changed line.)\n> +\tfor my $line (@{$rhunk->{TEXT}}) {\n> +\t\tif ($line =~ m/^[+-]/) {\n\nEven if it is a blank line?\n\n> +\t\t\t$summary .= $line;\n> +\t\t\tlast;\n> +\t\t}\n> +\t}\n> +\n> +\treturn substr ($summary, 0, 80);\n\ns/str /str/;\n\nHow well does substr() work with utf-8 and other multi-byte encodings\nthese days, I have to wonder...\n\n> +}\n> +\n> +\n> +# Print a one-line summary of each hunk in the array ref in\n> +# the first argument, starting wih the index in the 2nd.\n> +sub display_hunks {\n> +\tmy ($hunks, $i) = @_;\n> +\tmy $ctr = 0;\n> +\t$i = 0 if not $i;\n\nI think \"$i ||= 0\" is more common.\n\n> +\t\t\t$status,\n> +\t\t\t$i + 1,\n> +\t\t\tsummarize_hunk ($hunks->[$i]);\n\ns/_hunk /_hunk/;\n"},{"id":"97113","messageId":"7v4p1kalno.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"4936EE68.6030009@gmail.com","subject":"Re: summaries in git add --patch[PATCH 2/2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-03T23:23:07Z","receivedAt":"2008-12-03T23:23:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> From 57b5eab3f64a40ebe9aca122b5c6db1ab5c26116 Mon Sep 17 00:00:00 2001\n> From: William Pursell <bill.pursell@gmail.com>\n> Date: Wed, 3 Dec 2008 20:26:36 +0000\n> Subject: [PATCH 2/2] Implemented 'g' command to goto a hunk.\n\ns/ted/t/; or s/Implemented/Add/;\ns/goto/go to/;\n\n> When a minor change is made while the working directory is in a bit of a\n> mess (and the user should have done a stash before making the minor\n> edit, but didn't) it is somewhat difficult to wade through all of the\n> hunks using git add --patch.  This allows one to jump to the hunk that\n> needs to be staged without having to respond 'n' to each preceding hunk.\n\nYeah, even without forgotten stashing, you can be in a situation where you\nsimply have many many changes all over in a file, and know exactly how the\none you need to add to the index urgently looks like.\n\n> @@ -976,6 +980,27 @@ sub patch_update_file {\n>  \t\t\t\t}\n>  \t\t\t\tnext;\n>  \t\t\t}\n> +\t\t\telsif ($other =~ 'g' && $line =~ /^g(.*)/) {\n> +\t\t\t\tmy $response = $1;\n> +\t\t\t\tmy $i = 0;\n> +\t\t\t\tchomp $response;\n> +\t\t\t\twhile (not $response) {\n\nDid you mean \"while ($response eq '')\"?  I do not think you want \"g0<ret>\"\nto fall into the loop.\n\n> +\t\t\t\t\tmy $extra = \"\";\n> +\t\t\t\t\t$i = display_hunks (\\@hunk, $i);\n\ns/_hunks /_hunks/;\n\n> +\t\t\t\t\t$extra = \"(<ret> to see more): \" if ($i != $num);\n\nThis is probably just a matter of taste, but (1) Statement Modifiers are\nmuch harder to read than straightforward conditional blocks, and (2) loop\ntermination condition is better written with magnitude comparison not with\nunequality test, when the variable approaches to the limit always from a\nknown direction, so:\n\n\tif ($i < $num) {\n        \t$extra = \"(<ret> to see more): \";\n\t}\n\n> +\t\t\t\t\tprint \"goto which hunk? $extra\";\n\nThis placement of $extra looks a bit odd.\n\n\tgoto which hunk? (<ret> to see more): *cursor blinking here*\n        goto which hunk? *cursor blinking here*\n\nShouldn't it be like this?\n\n\tgoto which hunk (<ret> to see more)? *cursor blinking here*\n\n> +\t\t\t\t\t$response = <STDIN>;\n> +\t\t\t\t\tchomp $response;\n> +\t\t\t\t}\n> +\t\t\t\tif ($response !~ /^\\s*\\d+$/) {\n\nWhy is \" 1<ret>\" allowed but not \"1 <ret>\"?\n\n> +\t\t\t\t\tprint STDERR \"Invalid number: '$response'\\n\";\n> +\t\t\t\t} elsif (0 < $response && $response <= $num) {\n> +\t\t\t\t\t$ix = $response - 1;\n> +\t\t\t\t} else {\n> +\t\t\t\t\tprint STDERR \"Sorry, only $num hunks available.\\n\";\n> +\t\t\t\t}\n> +\t\t\t\tnext;\n> +\t\t\t}\n>  \t\t\telsif ($line =~ /^d/i) {\n>  \t\t\t\twhile ($ix < $num) {\n>  \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n"},{"id":"97132","messageId":"49377ED8.4050905@gmail.com","threadId":"16503","inReplyTo":"7vd4g8alp7.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch[PATCH 1/2]","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-12-04T06:55:20Z","receivedAt":"2008-12-04T06:55:20Z","isPatch":true,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"Junio C Hamano wrote:\n\n> Do you really want the surrounding @@ in the result, by the way?\n\nOddly, I liked it before.  But now that you mention it, it does\nseem ugly.\n\n> How well does substr() work with utf-8 and other multi-byte encodings\n> these days, I have to wonder...\n\nHopefully, it works well.\n\nHere's another go, with your suggestions applied.\n\n\n From 92ab9b7c694ba98b43984bbbdfcd5eeb9cbb7d56 Mon Sep 17 00:00:00 2001\nFrom: William Pursell <bill.pursell@gmail.com>\nDate: Thu, 4 Dec 2008 06:09:50 +0000\nSubject: [PATCH 1/2] Add subroutine to display one-line summary of hunks.\n\nThis commit implements a rather simple-minded mechanism\nto display a one-line summary of the hunks in an array ref.\nThe display consists of the line numbers and the first\nchanged line, truncated to 80 characters.  20 lines are\ndisplayed at a time, and the index of the first undisplayed\nline is returned, allowing the caller to display more if\ndesired.  (The 20 and 80 should be made configurable.)\n\nSigned-off-by: William Pursell <bill.pursell@gmail.com>\n---\n  git-add--interactive.perl |   42 ++++++++++++++++++++++++++++++++++++++++++\n  1 files changed, 42 insertions(+), 0 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex b0223c3..b25a841 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -836,6 +836,48 @@ sub patch_update_cmd {\n  \t}\n  }\n\n+# Generate a one line summary of a hunk.\n+sub summarize_hunk {\n+\tmy $rhunk = shift;\n+\tmy $summary = $rhunk->{TEXT}[0];\n+\n+\t# Keep the line numbers, discard extra context.\n+\t$summary =~ s/@@(.*?)@@.*/$1 /s;\n+\t$summary .= \" \" x (20 - length $summary);\n+\n+\t# Add some user context, the first changed line that contains\n+\t# some non-white character other than a bracket.\n+\tfor my $line (@{$rhunk->{TEXT}}) {\n+\t\tif ($line =~ m/^([+-][][{}()\\s]*[^][{}()\\s])/) {\n+\t\t\t$summary .= $line;\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\tchomp $summary;\n+\treturn substr($summary, 0, 80) . \"\\n\";\n+}\n+\n+\n+# Print a one-line summary of each hunk in the array ref in\n+# the first argument, starting wih the index in the 2nd.\n+sub display_hunks {\n+\tmy ($hunks, $i) = @_;\n+\tmy $ctr = 0;\n+\t$i = 0 if not $i;\n+\tfor (; $i < @$hunks && $ctr < 20; $i++, $ctr++) {\n+\t\tmy $status = \" \";\n+\t\tif (defined $hunks->[$i]{USE}) {\n+\t\t\t$status = $hunks->[$i]{USE} ? \"+\" : \"-\";\n+\t\t}\n+\t\tprintf \"%s%2d: %s\",\n+\t\t\t$status,\n+\t\t\t$i + 1,\n+\t\t\tsummarize_hunk($hunks->[$i]);\n+\t}\n+\treturn $i;\n+}\n+\n  sub patch_update_file {\n  \tmy ($ix, $num);\n  \tmy $path = shift;\n-- \n1.6.1.rc1.37.g83daf.dirty\n\n\n\n-- \nWilliam Pursell\n"},{"id":"97133","messageId":"49377F25.9020005@gmail.com","threadId":"16503","inReplyTo":"7v4p1kalno.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch[PATCH 2/2]","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-12-04T06:56:37Z","receivedAt":"2008-12-04T06:56:37Z","isPatch":true,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":" From b039fb8aa03efab3faf46c0a0a8d84cea974f26f Mon Sep 17 00:00:00 2001\nFrom: William Pursell <bill.pursell@gmail.com>\nDate: Thu, 4 Dec 2008 06:48:57 +0000\nSubject: [PATCH 2/2] Add 'g' command to go to a hunk.\n\nWhen a minor change is made while the working directory\nis in a bit of a mess (and the user should have done a\nstash before making the minor edit, but didn't) it is\nsomewhat difficult to wade through all of the hunks using\ngit add --patch.  This allows one to jump to the hunk\nthat needs to be staged without having to respond 'n' to\neach preceding hunk.\n\nSigned-off-by: William Pursell <bill.pursell@gmail.com>\n---\n  git-add--interactive.perl |   26 ++++++++++++++++++++++++++\n  1 files changed, 26 insertions(+), 0 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex b25a841..555c981 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -800,6 +800,7 @@ y - stage this hunk\n  n - do not stage this hunk\n  a - stage this and all the remaining hunks in the file\n  d - do not stage this hunk nor any of the remaining hunks in the file\n+g - select a hunk to goto\n  j - leave this hunk undecided, see next undecided hunk\n  J - leave this hunk undecided, see next hunk\n  k - leave this hunk undecided, see previous undecided hunk\n@@ -946,6 +947,9 @@ sub patch_update_file {\n  \t\tif ($ix < $num - 1) {\n  \t\t\t$other .= '/J';\n  \t\t}\n+\t\tif ($num > 1) {\n+\t\t\t$other .= '/g';\n+\t\t}\n  \t\tfor ($i = 0; $i < $num; $i++) {\n  \t\t\tif (!defined $hunk[$i]{USE}) {\n  \t\t\t\t$undecided = 1;\n@@ -979,6 +983,28 @@ sub patch_update_file {\n  \t\t\t\t}\n  \t\t\t\tnext;\n  \t\t\t}\n+\t\t\telsif ($other =~ 'g' && $line =~ /^g(.*)/) {\n+\t\t\t\tmy $response = $1;\n+\t\t\t\tmy $i = $ix > 10 ? $ix - 10 : 0;\n+\t\t\t\twhile ($response eq '') {\n+\t\t\t\t\tmy $extra = \"\";\n+\t\t\t\t\t$i = display_hunks(\\@hunk, $i);\n+\t\t\t\t\tif ($i < $num) {\n+\t\t\t\t\t\t$extra = \" (<ret> to see more)\";\n+\t\t\t\t\t}\n+\t\t\t\t\tprint \"goto which hunk$extra? \";\n+\t\t\t\t\t$response = <STDIN>;\n+\t\t\t\t\tchomp $response;\n+\t\t\t\t}\n+\t\t\t\tif ($response !~ /^\\s*\\d+\\s*$/) {\n+\t\t\t\t\tprint STDERR \"Invalid number: '$response'\\n\";\n+\t\t\t\t} elsif (0 < $response && $response <= $num) {\n+\t\t\t\t\t$ix = $response - 1;\n+\t\t\t\t} else {\n+\t\t\t\t\tprint STDERR \"Sorry, only $num hunks available.\\n\";\n+\t\t\t\t}\n+\t\t\t\tnext;\n+\t\t\t}\n  \t\t\telsif ($line =~ /^d/i) {\n  \t\t\t\twhile ($ix < $num) {\n  \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n-- \n1.6.1.rc1.37.g83daf.dirty\n"},{"id":"97135","messageId":"7vvdu0e38a.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"49377ED8.4050905@gmail.com","subject":"Re: summaries in git add --patch[PATCH 1/2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-04T08:47:33Z","receivedAt":"2008-12-04T08:47:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n>> How well does substr() work with utf-8 and other multi-byte encodings\n>> these days, I have to wonder...\n>\n> Hopefully, it works well.\n\n\"Hopefully\" is the last word I'd like to hear from submitters.  It would\nbe either \"I do not know\" or \"I studied the topic and I know the code works\".\n\n> Here's another go, with your suggestions applied.\n\nSorry, this came too late for tonight's round.  I have a fixed-up one\nbased on your previous round parked in 'pu', which I'll be replacing with\nthis one (or your future re-submission if there is any) later in the week.\n\nBy the way, I noticed that you are sending your patches with:\n\n    Content-Type: text/plain; charset=ISO-8859-1; format=flowed\n\nPlease don't.  format=flawed tends to destroy whitespaces (I fixed them up\nby hand for the ones I parked in 'pu').\n\n> +\t# Add some user context, the first changed line that contains\n> +\t# some non-white character other than a bracket.\n> +\tfor my $line (@{$rhunk->{TEXT}}) {\n> +\t\tif ($line =~ m/^([+-][][{}()\\s]*[^][{}()\\s])/) {\n\nI would say \"$line =~ /^[-+].*\\w/\" (i.e. match any +/- line that contains\na word letter) would be sufficient, and it would be much easier to read.\n\nAs you append the entire $line to $summary, there is no need to capture\nwith ().\n\n> +# Print a one-line summary of each hunk in the array ref in\n> +# the first argument, starting wih the index in the 2nd.\n> +sub display_hunks {\n> +\tmy ($hunks, $i) = @_;\n> +\tmy $ctr = 0;\n> +\t$i = 0 if not $i;\n\nI think \"$i ||= 0\" is more customary.\n"},{"id":"97136","messageId":"7vljuwe2na.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"49377F25.9020005@gmail.com","subject":"Re: summaries in git add --patch[PATCH 2/2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-04T09:00:09Z","receivedAt":"2008-12-04T09:00:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> From b039fb8aa03efab3faf46c0a0a8d84cea974f26f Mon Sep 17 00:00:00 2001\n> From: William Pursell <bill.pursell@gmail.com>\n> Date: Thu, 4 Dec 2008 06:48:57 +0000\n> Subject: [PATCH 2/2] Add 'g' command to go to a hunk.\n>\n> When a minor change is made while the working directory\n> is in a bit of a mess (and the user should have done a\n> stash before making the minor edit, but didn't) it is\n> somewhat difficult to wade through all of the hunks using\n> git add --patch.  This allows one to jump to the hunk\n> that needs to be staged without having to respond 'n' to\n> each preceding hunk.\n\nThe issue is not limited to \"forgot to stash\" situation.\n\n> Signed-off-by: William Pursell <bill.pursell@gmail.com>\n> ---\n\nIt is customary to explain what you changed since v1 here, after the\nthree-dash separator, to help reviewers.\n\n>  git-add--interactive.perl |   26 ++++++++++++++++++++++++++\n>  1 files changed, 26 insertions(+), 0 deletions(-)\n>\n> diff --git a/git-add--interactive.perl b/git-add--interactive.perl\n> index b25a841..555c981 100755\n> --- a/git-add--interactive.perl\n> +++ b/git-add--interactive.perl\n> @@ -800,6 +800,7 @@ y - stage this hunk\n>  n - do not stage this hunk\n>  a - stage this and all the remaining hunks in the file\n>  d - do not stage this hunk nor any of the remaining hunks in the file\n> +g - select a hunk to goto\n\n\"go to\"?  There are a few more.\n\n>  j - leave this hunk undecided, see next undecided hunk\n>  J - leave this hunk undecided, see next hunk\n>  k - leave this hunk undecided, see previous undecided hunk\n> @@ -946,6 +947,9 @@ sub patch_update_file {\n>  \t\tif ($ix < $num - 1) {\n>  \t\t\t$other .= '/J';\n>  \t\t}\n> +\t\tif ($num > 1) {\n> +\t\t\t$other .= '/g';\n> +\t\t}\n>  \t\tfor ($i = 0; $i < $num; $i++) {\n>  \t\t\tif (!defined $hunk[$i]{USE}) {\n>  \t\t\t\t$undecided = 1;\n> @@ -979,6 +983,28 @@ sub patch_update_file {\n>  \t\t\t\t}\n>  \t\t\t\tnext;\n>  \t\t\t}\n> +\t\t\telsif ($other =~ 'g' && $line =~ /^g(.*)/) {\n\nI think I fixed this with ($other =~ /g/ && ...) when I queued your\nprevious round to 'pu' tonight.\n\n> +\t\t\t\tmy $response = $1;\n> +\t\t\t\tmy $i = $ix > 10 ? $ix - 10 : 0;\n\nThis is different from v1.  I understand the motivation (i.e. if you are\nat 73rd hunk of a 100-hunk series, showing hunks 63-83 instead of starting\nfrom hunk 1-10 would be nicer), but that is something to explain as one of\nthe \"changes since v1\".\n\nI think you are inside a loop that is controlled by another $i (see the\ncontext in the hunk before this one) and it would be better to use\ndifferent variable, such as $hunk_no (or just $no).\n\n> +\t\t\t\twhile ($response eq '') {\n> +\t\t\t\t\tmy $extra = \"\";\n> +\t\t\t\t\t$i = display_hunks(\\@hunk, $i);\n> +\t\t\t\t\tif ($i < $num) {\n> +\t\t\t\t\t\t$extra = \" (<ret> to see more)\";\n> +\t\t\t\t\t}\n> +\t\t\t\t\tprint \"goto which hunk$extra? \";\n\n\"go to\"?\n\nAgain, this came too late for tonight's round.  I've parked your previous\none with fix-up in 'pu', but you are free to tell me to replace it\n(together with [1/2] from your previous round) with an updated pair.\n"},{"id":"97142","messageId":"4937B456.7080604@gmail.com","threadId":"16503","inReplyTo":"7vvdu0e38a.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch[PATCH 1/2]","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-12-04T10:43:34Z","receivedAt":"2008-12-04T10:43:34Z","isPatch":true,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> William Pursell <bill.pursell@gmail.com> writes:\n> \n>>> How well does substr() work with utf-8 and other multi-byte encodings\n>>> these days, I have to wonder...\n>> Hopefully, it works well.\n> \n> \"Hopefully\" is the last word I'd like to hear from submitters.  It would\n> be either \"I do not know\" or \"I studied the topic and I know the code works\".\n\nRight.  From what I can tell (30 minutes of research, and I\nam by no means an expert), perl 5.8 will handle this just\nfine with no changes to the code as long as one of the\nenvironment variables LANGUAGE, LC_ALL, LC_TYPE, or LANG\ncontains either 'UTF-8' or 'UTF8'.  With that setting,\nall file handles will be opened in UTF8 mode, so the\ngit diff-files pipe should be parsed appropriately.\nI think this is not an issue except with older Perl.\n\n> By the way, I noticed that you are sending your patches with:\n> \n>     Content-Type: text/plain; charset=ISO-8859-1; format=flowed\n> \n> Please don't.  format=flawed tends to destroy whitespaces (I fixed them up\n> by hand for the ones I parked in 'pu').\n\nThanks for pointing that out.  Settings changed.  I do appreciate\nyou taking the time to essentially hold my hand through this\nprocess, and hope that I'm not causing you too much extra work.\n\n> I would say \"$line =~ /^[-+].*\\w/\" (i.e. match any +/- line that contains\n> a word letter) would be sufficient, and it would be much easier to read.\n> \n> As you append the entire $line to $summary, there is no need to capture\n> with ().\n\nDone.\n\n> \n> I think \"$i ||= 0\" is more customary.\n> \nAlso changed.\n\n\n>From 2d191d7170948246007cbde5afb28eeb666b3427 Mon Sep 17 00:00:00 2001\nFrom: William Pursell <bill.pursell@gmail.com>\nDate: Thu, 4 Dec 2008 10:00:24 +0000\nSubject: [PATCH 1/2] Add subroutine to display one-line summary of hunks.\n\nThis commit implements a rather simple-minded mechanism\nto display a one-line summary of the hunks in an array ref.\nThe display consists of the line numbers and the first\nchanged line, truncated to 80 characters.  20 lines are\ndisplayed at a time, and the index of the first undisplayed\nline is returned, allowing the caller to display more if\ndesired.  (The 20 and 80 should be made configurable.)\n\nSigned-off-by: William Pursell <bill.pursell@gmail.com>\n\n---\nchanges from v1:\n  do not print '@@' characters in summary\n  pad line numbers in summary to 20 chars to help alignment\n  only accept diff lines with a non-space, non-bracket character\n  ensure a newline appears on a trimmed line\nchanges from v2:\n  accept any line with a word char (instead of insisting on non-bracket)\n  use \"$i || = 0\" instead of \"$i = 0 if not $i\"\n\n git-add--interactive.perl |   41 +++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 41 insertions(+), 0 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex b0223c3..eb11132 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -836,6 +836,47 @@ sub patch_update_cmd {\n \t}\n }\n\n+# Generate a one line summary of a hunk.\n+sub summarize_hunk {\n+\tmy $rhunk = shift;\n+\tmy $summary = $rhunk->{TEXT}[0];\n+\n+\t# Keep the line numbers, discard extra context.\n+\t$summary =~ s/@@(.*?)@@.*/$1 /s;\n+\t$summary .= \" \" x (20 - length $summary);\n+\n+\t# Add some user context.\n+\tfor my $line (@{$rhunk->{TEXT}}) {\n+\t\tif ($line =~ m/^[+-].*\\w/) {\n+\t\t\t$summary .= $line;\n+\t\t\tlast;\n+\t\t}\n+\t}\n+\n+\tchomp $summary;\n+\treturn substr($summary, 0, 80) . \"\\n\";\n+}\n+\n+\n+# Print a one-line summary of each hunk in the array ref in\n+# the first argument, starting wih the index in the 2nd.\n+sub display_hunks {\n+\tmy ($hunks, $i) = @_;\n+\tmy $ctr = 0;\n+\t$i ||= 0;\n+\tfor (; $i < @$hunks && $ctr < 20; $i++, $ctr++) {\n+\t\tmy $status = \" \";\n+\t\tif (defined $hunks->[$i]{USE}) {\n+\t\t\t$status = $hunks->[$i]{USE} ? \"+\" : \"-\";\n+\t\t}\n+\t\tprintf \"%s%2d: %s\",\n+\t\t\t$status,\n+\t\t\t$i + 1,\n+\t\t\tsummarize_hunk($hunks->[$i]);\n+\t}\n+\treturn $i;\n+}\n+\n sub patch_update_file {\n \tmy ($ix, $num);\n \tmy $path = shift;\n-- \n1.6.1.rc1.37.g83daf.dirty\n\n\n-- \nWilliam Pursell\n"},{"id":"97141","messageId":"4937B45C.1080801@gmail.com","threadId":"16503","inReplyTo":"7vljuwe2na.fsf@gitster.siamese.dyndns.org","subject":"Re: summaries in git add --patch[PATCH 2/2]","fromName":"William Pursell","fromEmail":"bill.pursell@gmail.com","sentAt":"2008-12-04T10:43:40Z","receivedAt":"2008-12-04T10:43:40Z","isPatch":true,"sender":{"key":"bill.pursell@gmail.com","avatar":"https://gravatar.com/avatar/3ab4313e5dfdc1fedb65206d829ba33f71f56f26e11326979d1b99d5e1c403c9?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> William Pursell <bill.pursell@gmail.com> writes:\n\n>> Signed-off-by: William Pursell <bill.pursell@gmail.com>\n>> ---\n> \n> It is customary to explain what you changed since v1 here, after the\n> three-dash separator, to help reviewers.\n\nThanks for pointing that out.\n\n>> +\t\t\telsif ($other =~ 'g' && $line =~ /^g(.*)/) {\n> \n> I think I fixed this with ($other =~ /g/ && ...) when I queued your\n> previous round to 'pu' tonight.\n\nI didn't notice that the first time around.  Fixed here.\n> \n>> +\t\t\t\tmy $response = $1;\n>> +\t\t\t\tmy $i = $ix > 10 ? $ix - 10 : 0;\n> \n> This is different from v1.  I understand the motivation (i.e. if you are\n> at 73rd hunk of a 100-hunk series, showing hunks 63-83 instead of starting\n> from hunk 1-10 would be nicer), but that is something to explain as one of\n> the \"changes since v1\".\n> \n> I think you are inside a loop that is controlled by another $i (see the\n> context in the hunk before this one) and it would be better to use\n> different variable, such as $hunk_no (or just $no).\n\nAgreed.  Masking enclosing variables is a no-no.\n\n\n>From 03ae1932337c15cdd20e0d8370782a6343efc5aa Mon Sep 17 00:00:00 2001\nFrom: William Pursell <bill.pursell@gmail.com>\nDate: Thu, 4 Dec 2008 10:22:40 +0000\nSubject: [PATCH 2/2] Add 'g' command to go to a hunk.\n\nWhen a minor change is made while the working directory is in a bit\nof a mess,  it is somewhat difficult to wade through all of the\nhunks using git add --patch.  This allows one to jump to the hunk\nthat needs to be staged without having to respond 'n' to each\npreceding hunk.\n\nSigned-off-by: William Pursell <bill.pursell@gmail.com>\n\n---\nchanges since v1:\n  start the summary list from current hunk - 10 rather than 0\n  replace a statement modifier with a conditional block, for readability\n  clean up the prompt, so \"(<ret> to see more)\" appears before '?'\n  allow trailing whitespace in the user response\nchanges since v2:\n  s/goto/go to/\n  s|=~ 'g'|=~ /g/|\n  change loop index name from $i to $no, as $i masks a name in the enclosing\n    scope\n\n\n git-add--interactive.perl |   26 ++++++++++++++++++++++++++\n 1 files changed, 26 insertions(+), 0 deletions(-)\n\ndiff --git a/git-add--interactive.perl b/git-add--interactive.perl\nindex eb11132..ca60356 100755\n--- a/git-add--interactive.perl\n+++ b/git-add--interactive.perl\n@@ -800,6 +800,7 @@ y - stage this hunk\n n - do not stage this hunk\n a - stage this and all the remaining hunks in the file\n d - do not stage this hunk nor any of the remaining hunks in the file\n+g - select a hunk to go to\n j - leave this hunk undecided, see next undecided hunk\n J - leave this hunk undecided, see next hunk\n k - leave this hunk undecided, see previous undecided hunk\n@@ -945,6 +946,9 @@ sub patch_update_file {\n \t\tif ($ix < $num - 1) {\n \t\t\t$other .= '/J';\n \t\t}\n+\t\tif ($num > 1) {\n+\t\t\t$other .= '/g';\n+\t\t}\n \t\tfor ($i = 0; $i < $num; $i++) {\n \t\t\tif (!defined $hunk[$i]{USE}) {\n \t\t\t\t$undecided = 1;\n@@ -978,6 +982,28 @@ sub patch_update_file {\n \t\t\t\t}\n \t\t\t\tnext;\n \t\t\t}\n+\t\t\telsif ($other =~ /g/ && $line =~ /^g(.*)/) {\n+\t\t\t\tmy $response = $1;\n+\t\t\t\tmy $no = $ix > 10 ? $ix - 10 : 0;\n+\t\t\t\twhile ($response eq '') {\n+\t\t\t\t\tmy $extra = \"\";\n+\t\t\t\t\t$no = display_hunks(\\@hunk, $no);\n+\t\t\t\t\tif ($no < $num) {\n+\t\t\t\t\t\t$extra = \" (<ret> to see more)\";\n+\t\t\t\t\t}\n+\t\t\t\t\tprint \"go to which hunk$extra? \";\n+\t\t\t\t\t$response = <STDIN>;\n+\t\t\t\t\tchomp $response;\n+\t\t\t\t}\n+\t\t\t\tif ($response !~ /^\\s*\\d+\\s*$/) {\n+\t\t\t\t\tprint STDERR \"Invalid number: '$response'\\n\";\n+\t\t\t\t} elsif (0 < $response && $response <= $num) {\n+\t\t\t\t\t$ix = $response - 1;\n+\t\t\t\t} else {\n+\t\t\t\t\tprint STDERR \"Sorry, only $num hunks available.\\n\";\n+\t\t\t\t}\n+\t\t\t\tnext;\n+\t\t\t}\n \t\t\telsif ($line =~ /^d/i) {\n \t\t\t\twhile ($ix < $num) {\n \t\t\t\t\tif (!defined $hunk[$ix]{USE}) {\n-- \n1.6.1.rc1.37.g83daf.dirty\n\n\n\n\n-- \nWilliam Pursell\n"},{"id":"97199","messageId":"7viqpz1hsa.fsf@gitster.siamese.dyndns.org","threadId":"16503","inReplyTo":"4937B456.7080604@gmail.com","subject":"Re: summaries in git add --patch[PATCH 1/2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-05T02:23:49Z","receivedAt":"2008-12-05T02:23:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"William Pursell <bill.pursell@gmail.com> writes:\n\n> Thanks for pointing that out.  Settings changed.  I do appreciate\n> you taking the time to essentially hold my hand through this\n> process, and hope that I'm not causing you too much extra work.\n\nHeh, I'll be saving extra work I have to do in the future by training you\nhow to produce patches line the ones I may write myself.  By doing so,\neventually I wouldn't have to code anything myself ;-)\n\n> +# Generate a one line summary of a hunk.\n> +sub summarize_hunk {\n> +\tmy $rhunk = shift;\n> +\tmy $summary = $rhunk->{TEXT}[0];\n> +\n> +\t# Keep the line numbers, discard extra context.\n> +\t$summary =~ s/@@(.*?)@@.*/$1 /s;\n> +\t$summary .= \" \" x (20 - length $summary);\n> +\n> +\t# Add some user context.\n> +\tfor my $line (@{$rhunk->{TEXT}}) {\n> +\t\tif ($line =~ m/^[+-].*\\w/) {\n> +\t\t\t$summary .= $line;\n> +\t\t\tlast;\n> +\t\t}\n> +\t}\n> +\n> +\tchomp $summary;\n> +\treturn substr($summary, 0, 80) . \"\\n\";\n> +}\n\nI'll queue the patches in this round as-is in 'pu' and merge to 'next', as\nwe should stop slushing around at some point and start polishing on a\nsolid ground.  But as you mentioned, these hardcoded 20 and 80 do not look\nvery nice.\n\nI think the division of labor between the data producer (summarize_hunk)\nand presenter (display_hunks) should be shifted somewhat, so that\n\n * summarize_hunk returns a two-tuple:\n\n\t[ $line_number_hint, $first_change ]\n\n * display_hunks runs summarize_hunk for all 20 hunks and gathers the\n   return values before producing a single line of output, and then\n   computes the maximum $line_number_hint to decide how many extra SP to\n   use to pad it to uniform length (instead of \" \" x (20 - length)).\n   After doing so, it loops over the hunks, using the collected return\n   values and formats.\n\nIn later round of polishing, you might find out that some callers of\nsummarize_hunk may want to read the full line, not just the first 80\n(perhaps they feed their output to \"less -S\").  By splitting the\nresponsibility between these functions in the way outlined above, you do\nnot have to modify summarize_hunk when that day comes.\n\n> +\n> +\n> +# Print a one-line summary of each hunk in the array ref in\n> +# the first argument, starting wih the index in the 2nd.\n> +sub display_hunks {\n> +\tmy ($hunks, $i) = @_;\n> +\tmy $ctr = 0;\n> +\t$i ||= 0;\n> +\tfor (; $i < @$hunks && $ctr < 20; $i++, $ctr++) {\n> +\t\tmy $status = \" \";\n> +\t\tif (defined $hunks->[$i]{USE}) {\n> +\t\t\t$status = $hunks->[$i]{USE} ? \"+\" : \"-\";\n> +\t\t}\n> +\t\tprintf \"%s%2d: %s\",\n> +\t\t\t$status,\n> +\t\t\t$i + 1,\n> +\t\t\tsummarize_hunk($hunks->[$i]);\n> +\t}\n\nBy the way, I do not think this will align if you have more than 100\nhunks.  That is also a reason why I would suggest not to format/substr\ninside the summarize_hunk function.\n"}]}