@@ -2202,31 +2202,56 @@ sub git_patchset_body {
22022202 my ($fd , $difftree , $hash , $hash_parent ) = @_ ;
22032203
22042204 my $patch_idx = 0;
2205- my $in_header = 0;
2206- my $patch_found = 0;
2205+ my $patch_line ;
22072206 my $diffinfo ;
22082207 my (%from , %to );
2208+ my ($from_id , $to_id );
22092209
22102210 print " <div class=\" patchset\" >\n " ;
22112211
2212- LINE:
2213- while (my $patch_line = <$fd >) {
2212+ # skip to first patch
2213+ while ($patch_line = <$fd >) {
22142214 chomp $patch_line ;
22152215
2216- if ($patch_line =~ m / ^diff / ) { # "git diff" header
2217- # beginning of patch (in patchset)
2218- if ($patch_found ) {
2219- # close extended header for previous empty patch
2220- if ($in_header ) {
2221- print " </div>\n " # class="diff extended_header"
2222- }
2223- # close previous patch
2224- print " </div>\n " ; # class="patch"
2225- } else {
2226- # first patch in patchset
2227- $patch_found = 1;
2216+ last if ($patch_line =~ m / ^diff / );
2217+ }
2218+
2219+ PATCH:
2220+ while ($patch_line ) {
2221+ my @diff_header ;
2222+
2223+ # git diff header
2224+ # assert($patch_line =~ m/^diff /) if DEBUG;
2225+ # assert($patch_line !~ m!$/$!) if DEBUG; # is chomp-ed
2226+ push @diff_header , $patch_line ;
2227+
2228+ # extended diff header
2229+ EXTENDED_HEADER:
2230+ while ($patch_line = <$fd >) {
2231+ chomp $patch_line ;
2232+
2233+ last EXTENDED_HEADER if ($patch_line =~ m / ^--- / );
2234+
2235+ if ($patch_line =~ m / ^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/ ) {
2236+ $from_id = $1 ;
2237+ $to_id = $2 ;
22282238 }
2229- print " <div class=\" patch\" id=\" patch" . ($patch_idx +1) ." \" >\n " ;
2239+
2240+ push @diff_header , $patch_line ;
2241+ }
2242+ # last PATCH unless $patch_line;
2243+ my $last_patch_line = $patch_line ;
2244+
2245+ # check if current patch belong to current raw line
2246+ # and parse raw git-diff line if needed
2247+ if (defined $diffinfo &&
2248+ $diffinfo -> {' from_id' } eq $from_id &&
2249+ $diffinfo -> {' to_id' } eq $to_id ) {
2250+ # this is split patch
2251+ print " <div class=\" patch cont\" >\n " ;
2252+ } else {
2253+ # advance raw git-diff output if needed
2254+ $patch_idx ++ if defined $diffinfo ;
22302255
22312256 # read and prepare patch information
22322257 if (ref ($difftree -> [$patch_idx ]) eq " HASH" ) {
@@ -2247,100 +2272,112 @@ sub git_patchset_body {
22472272 hash => $diffinfo -> {' to_id' },
22482273 file_name => $to {' file' });
22492274 }
2250- $patch_idx ++;
2251-
2252- # print "git diff" header
2253- $patch_line =~ s ! ^(diff (.*?) )"?a/.*$! $1 ! ;
2254- if ($from {' href' }) {
2255- $patch_line .= $cgi -> a({-href => $from {' href' }, -class => " path" },
2256- ' a/' . esc_path($from {' file' }));
2257- } else { # file was added
2258- $patch_line .= ' a/' . esc_path($from {' file' });
2259- }
2260- $patch_line .= ' ' ;
2261- if ($to {' href' }) {
2262- $patch_line .= $cgi -> a({-href => $to {' href' }, -class => " path" },
2263- ' b/' . esc_path($to {' file' }));
2264- } else { # file was deleted
2265- $patch_line .= ' b/' . esc_path($to {' file' });
2266- }
2267-
2268- print " <div class=\" diff header\" >$patch_line </div>\n " ;
2269- print " <div class=\" diff extended_header\" >\n " ;
2270- $in_header = 1;
2271- next LINE;
2275+ # this is first patch for raw difftree line with $patch_idx index
2276+ # we index @$difftree array from 0, but number patches from 1
2277+ print " <div class=\" patch\" id=\" patch" . ($patch_idx +1) ." \" >\n " ;
22722278 }
22732279
2274- if ($in_header ) {
2275- if ($patch_line !~ m / ^---/ ) {
2276- # match <path>
2277- if ($patch_line =~ s ! ^((copy|rename) from ).*$! $1 ! && $from {' href' }) {
2278- $patch_line .= $cgi -> a({-href => $from {' href' }, -class => " path" },
2279- esc_path($from {' file' }));
2280- }
2281- if ($patch_line =~ s ! ^((copy|rename) to ).*$! $1 ! && $to {' href' }) {
2282- $patch_line = $cgi -> a({-href => $to {' href' }, -class => " path" },
2283- esc_path($to {' file' }));
2284- }
2285- # match <mode>
2286- if ($patch_line =~ m /\s (\d {6})$ / ) {
2287- $patch_line .= ' <span class="info"> (' .
2288- file_type_long($1 ) .
2289- ' )</span>' ;
2280+ # print "git diff" header
2281+ $patch_line = shift @diff_header ;
2282+ $patch_line =~ s ! ^(diff (.*?) )"?a/.*$! $1 ! ;
2283+ if ($from {' href' }) {
2284+ $patch_line .= $cgi -> a({-href => $from {' href' }, -class => " path" },
2285+ ' a/' . esc_path($from {' file' }));
2286+ } else { # file was added
2287+ $patch_line .= ' a/' . esc_path($from {' file' });
2288+ }
2289+ $patch_line .= ' ' ;
2290+ if ($to {' href' }) {
2291+ $patch_line .= $cgi -> a({-href => $to {' href' }, -class => " path" },
2292+ ' b/' . esc_path($to {' file' }));
2293+ } else { # file was deleted
2294+ $patch_line .= ' b/' . esc_path($to {' file' });
2295+ }
2296+ print " <div class=\" diff header\" >$patch_line </div>\n " ;
2297+
2298+ # print extended diff header
2299+ print " <div class=\" diff extended_header\" >\n " if (@diff_header > 0);
2300+ EXTENDED_HEADER:
2301+ foreach $patch_line (@diff_header ) {
2302+ # match <path>
2303+ if ($patch_line =~ s ! ^((copy|rename) from ).*$! $1 ! && $from {' href' }) {
2304+ $patch_line .= $cgi -> a({-href => $from {' href' }, -class => " path" },
2305+ esc_path($from {' file' }));
2306+ }
2307+ if ($patch_line =~ s ! ^((copy|rename) to ).*$! $1 ! && $to {' href' }) {
2308+ $patch_line = $cgi -> a({-href => $to {' href' }, -class => " path" },
2309+ esc_path($to {' file' }));
2310+ }
2311+ # match <mode>
2312+ if ($patch_line =~ m /\s (\d {6})$ / ) {
2313+ $patch_line .= ' <span class="info"> (' .
2314+ file_type_long($1 ) .
2315+ ' )</span>' ;
2316+ }
2317+ # match <hash>
2318+ if ($patch_line =~ m / ^index/ ) {
2319+ my ($from_link , $to_link );
2320+ if ($from {' href' }) {
2321+ $from_link = $cgi -> a({-href => $from {' href' }, -class => " hash" },
2322+ substr ($diffinfo -> {' from_id' },0,7));
2323+ } else {
2324+ $from_link = ' 0' x 7 ;
22902325 }
2291- # match <hash>
2292- if ($patch_line =~ m / ^index/ ) {
2293- my ($from_link , $to_link );
2294- if ($from {' href' }) {
2295- $from_link = $cgi -> a({-href => $from {' href' }, -class => " hash" },
2296- substr ($diffinfo -> {' from_id' },0,7));
2297- } else {
2298- $from_link = ' 0' x 7 ;
2299- }
2300- if ($to {' href' }) {
2301- $to_link = $cgi -> a({-href => $to {' href' }, -class => " hash" },
2302- substr ($diffinfo -> {' to_id' },0,7));
2303- } else {
2304- $to_link = ' 0' x 7 ;
2305- }
2306- my ($from_id , $to_id ) = ($diffinfo -> {' from_id' }, $diffinfo -> {' to_id' });
2307- $patch_line =~ s ! $from_id\.\. $to_id! $from_link ..$to_link ! ;
2326+ if ($to {' href' }) {
2327+ $to_link = $cgi -> a({-href => $to {' href' }, -class => " hash" },
2328+ substr ($diffinfo -> {' to_id' },0,7));
2329+ } else {
2330+ $to_link = ' 0' x 7 ;
23082331 }
2309- print $patch_line . " <br/>\n " ;
2310-
2311- } else {
2312- # $in_header && $patch_line =~ m/^---/;
2313- print " </div>\n " ; # class="diff extended_header"
2314- $in_header = 0;
2332+ # affirm {
2333+ # my ($from_hash, $to_hash) =
2334+ # ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/);
2335+ # my ($from_id, $to_id) =
2336+ # ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
2337+ # ($from_hash eq $from_id) && ($to_hash eq $to_id);
2338+ # } if DEBUG;
2339+ my ($from_id , $to_id ) = ($diffinfo -> {' from_id' }, $diffinfo -> {' to_id' });
2340+ $patch_line =~ s ! $from_id\.\. $to_id! $from_link ..$to_link ! ;
2341+ }
2342+ print $patch_line . " <br/>\n " ;
2343+ }
2344+ print " </div>\n " if (@diff_header > 0); # class="diff extended_header"
2345+
2346+ # from-file/to-file diff header
2347+ $patch_line = $last_patch_line ;
2348+ # assert($patch_line =~ m/^---/) if DEBUG;
2349+ if ($from {' href' }) {
2350+ $patch_line = ' --- a/' .
2351+ $cgi -> a({-href => $from {' href' }, -class => " path" },
2352+ esc_path($from {' file' }));
2353+ }
2354+ print " <div class=\" diff from_file\" >$patch_line </div>\n " ;
23152355
2316- if ($from {' href' }) {
2317- $patch_line = ' --- a/' .
2318- $cgi -> a({-href => $from {' href' }, -class => " path" },
2319- esc_path($from {' file' }));
2320- }
2321- print " <div class=\" diff from_file\" >$patch_line </div>\n " ;
2356+ $patch_line = <$fd >;
2357+ # last PATCH unless $patch_line;
2358+ chomp $patch_line ;
23222359
2323- $patch_line = <$fd >;
2324- chomp $patch_line ;
2360+ # assert($patch_line =~ m/^+++/) if DEBUG;
2361+ if ($to {' href' }) {
2362+ $patch_line = ' +++ b/' .
2363+ $cgi -> a({-href => $to {' href' }, -class => " path" },
2364+ esc_path($to {' file' }));
2365+ }
2366+ print " <div class=\" diff to_file\" >$patch_line </div>\n " ;
23252367
2326- # $patch_line =~ m/^+++/;
2327- if ($to {' href' }) {
2328- $patch_line = ' +++ b/' .
2329- $cgi -> a({-href => $to {' href' }, -class => " path" },
2330- esc_path($to {' file' }));
2331- }
2332- print " <div class=\" diff to_file\" >$patch_line </div>\n " ;
2368+ # the patch itself
2369+ LINE:
2370+ while ($patch_line = <$fd >) {
2371+ chomp $patch_line ;
23332372
2334- }
2373+ next PATCH if ( $patch_line =~ m / ^diff / );
23352374
2336- next LINE ;
2375+ print format_diff_line( $patch_line ) ;
23372376 }
23382377
2339- print format_diff_line($patch_line );
2378+ } continue {
2379+ print " </div>\n " ; # class="patch"
23402380 }
2341- print " </div>\n " if $in_header ; # extended header
2342-
2343- print " </div>\n " if $patch_found ; # class="patch"
23442381
23452382 print " </div>\n " ; # class="patchset"
23462383}
0 commit comments