{"thread":{"id":"9745","subject":"[PATCH 3/5] gitweb: Add treediff view","startedAt":"2007-09-02T14:46:03Z","lastAt":"2007-09-04T06:31:51Z","messageCount":12,"participants":["Martin Koegler","Jakub Narebski","Petr Baudis","Junio C Hamano","Catalin Marinas"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"52200","messageId":"11887443682216-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"9745","inReplyTo":null,"subject":"[PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-02T14:46:03Z","receivedAt":"2007-09-02T14:46:03Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"Resend of the complete patch serie (again next).\n\nPatch 1-3 are unchanged.\n\nPatch 4 now only generates the links, if they are enabled.\nThe header contains a new link to show/hide the links.\nThe state is remembered via a cookie across pages.\n\nPatch 5 is the foundation for showing the base/diff links\nin an other color.\n\nmfg Martin Kögler\nPS:\nI develop the patches via StGit. If you think that I should publish them\nin a different way, please tell me.\n"},{"id":"52201","messageId":"11887443692839-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"9745","inReplyTo":"11887443682216-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 1/5] gitweb: Support comparing blobs with different names","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-02T14:46:04Z","receivedAt":"2007-09-02T14:46:04Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"Currently, blobdiff can only compare blobs with different file\nnames, if no hb/hpb parameters are present.\n\nThis patch adds support for comparing two blobs specified by any\ncombination of hb/f/h and hpb/fp/hp.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n gitweb/gitweb.perl |  148 +++++++++++++++++++---------------------------------\n 1 files changed, 53 insertions(+), 95 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex b2bae1b..05bfb26 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -4645,109 +4645,66 @@ sub git_blobdiff {\n \tmy $fd;\n \tmy @difftree;\n \tmy %diffinfo;\n-\tmy $expires;\n-\n-\t# preparing $fd and %diffinfo for git_patchset_body\n-\t# new style URI\n-\tif (defined $hash_base && defined $hash_parent_base) {\n-\t\tif (defined $file_name) {\n-\t\t\t# read raw output\n-\t\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t\t$hash_parent_base, $hash_base,\n-\t\t\t\t\"--\", (defined $file_parent ? $file_parent : ()), $file_name\n-\t\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n-\t\t\t@difftree = map { chomp; $_ } <$fd>;\n-\t\t\tclose $fd\n-\t\t\t\tor die_error(undef, \"Reading git-diff-tree failed\");\n-\t\t\t@difftree\n-\t\t\t\tor die_error('404 Not Found', \"Blob diff not found\");\n-\n-\t\t} elsif (defined $hash &&\n-\t\t         $hash =~ /[0-9a-fA-F]{40}/) {\n-\t\t\t# try to find filename from $hash\n-\n-\t\t\t# read filtered raw output\n-\t\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t\t$hash_parent_base, $hash_base, \"--\"\n-\t\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n-\t\t\t@difftree =\n-\t\t\t\t# ':100644 100644 03b21826... 3b93d5e7... M\tls-files.c'\n-\t\t\t\t# $hash == to_id\n-\t\t\t\tgrep { /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} $hash/ }\n-\t\t\t\tmap { chomp; $_ } <$fd>;\n-\t\t\tclose $fd\n-\t\t\t\tor die_error(undef, \"Reading git-diff-tree failed\");\n-\t\t\t@difftree\n-\t\t\t\tor die_error('404 Not Found', \"Blob diff not found\");\n+\tmy $expires = '+1d';\n+\tmy ($from, $to);\n \n-\t\t} else {\n-\t\t\tdie_error('404 Not Found', \"Missing one of the blob diff parameters\");\n-\t\t}\n-\n-\t\tif (@difftree > 1) {\n-\t\t\tdie_error('404 Not Found', \"Ambiguous blob diff specification\");\n-\t\t}\n+\t$file_parent ||= $file_name;\n \n-\t\t%diffinfo = parse_difftree_raw_line($difftree[0]);\n-\t\t$file_parent ||= $diffinfo{'from_file'} || $file_name || $diffinfo{'file'};\n-\t\t$file_name   ||= $diffinfo{'to_file'}   || $diffinfo{'file'};\n-\n-\t\t$hash_parent ||= $diffinfo{'from_id'};\n-\t\t$hash        ||= $diffinfo{'to_id'};\n-\n-\t\t# non-textual hash id's can be cached\n-\t\tif ($hash_base =~ m/^[0-9a-fA-F]{40}$/ &&\n-\t\t    $hash_parent_base =~ m/^[0-9a-fA-F]{40}$/) {\n-\t\t\t$expires = '+1d';\n-\t\t}\n+\t# non-textual hash id's can be cached\n+\tif (defined $hash && $hash !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent && $hash_parent !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_base && $hash_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent_base && $hash_parent_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t}\n+\n+\t# if hash parameter is missing, read it from the commit.\n+\tif (defined $hash_base && defined $file_name && !defined $hash) {\n+\t\t$hash = git_get_hash_by_path($hash_base, $file_name);\n+\t}\n \n-\t\t# open patch output\n-\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t'-p', ($format eq 'html' ? \"--full-index\" : ()),\n-\t\t\t$hash_parent_base, $hash_base,\n-\t\t\t\"--\", (defined $file_parent ? $file_parent : ()), $file_name\n-\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\tif (defined $hash_parent_base && defined $file_parent && !defined $hash_parent) {\n+\t    $hash_parent = git_get_hash_by_path($hash_parent_base, $file_parent);\n+\t}\n+\t\n+\tif (!defined $hash || ! defined $hash_parent) {\n+\t\tdie_error('404 Not Found', \"Missing one of the blob diff parameters\");\n \t}\n \n-\t# old/legacy style URI\n-\tif (!%diffinfo && # if new style URI failed\n-\t    defined $hash && defined $hash_parent) {\n-\t\t# fake git-diff-tree raw output\n-\t\t$diffinfo{'from_mode'} = $diffinfo{'to_mode'} = \"blob\";\n-\t\t$diffinfo{'from_id'} = $hash_parent;\n-\t\t$diffinfo{'to_id'}   = $hash;\n-\t\tif (defined $file_name) {\n-\t\t\tif (defined $file_parent) {\n-\t\t\t\t$diffinfo{'status'} = '2';\n-\t\t\t\t$diffinfo{'from_file'} = $file_parent;\n-\t\t\t\t$diffinfo{'to_file'}   = $file_name;\n-\t\t\t} else { # assume not renamed\n-\t\t\t\t$diffinfo{'status'} = '1';\n-\t\t\t\t$diffinfo{'from_file'} = $file_name;\n-\t\t\t\t$diffinfo{'to_file'}   = $file_name;\n-\t\t\t}\n-\t\t} else { # no filename given\n-\t\t\t$diffinfo{'status'} = '2';\n-\t\t\t$diffinfo{'from_file'} = $hash_parent;\n-\t\t\t$diffinfo{'to_file'}   = $hash;\n-\t\t}\n+\tif (defined $hash_base && defined $file_name) {\n+\t\t$to = $hash_base . ':' . $file_name;\n+\t} else {\n+\t\t$to = $hash;\n+\t}\n \n-\t\t# non-textual hash id's can be cached\n-\t\tif ($hash =~ m/^[0-9a-fA-F]{40}$/ &&\n-\t\t    $hash_parent =~ m/^[0-9a-fA-F]{40}$/) {\n-\t\t\t$expires = '+1d';\n-\t\t}\n+\tif (defined $hash_parent_base && defined $file_parent) {\n+\t\t$from = $hash_parent_base . ':' . $file_parent;\n+\t} else {\n+\t\t$from = $hash_parent;\n+\t}\n \n-\t\t# open patch output\n-\t\topen $fd, \"-|\", git_cmd(), \"diff\", @diff_opts,\n-\t\t\t'-p', ($format eq 'html' ? \"--full-index\" : ()),\n-\t\t\t$hash_parent, $hash, \"--\"\n-\t\t\tor die_error(undef, \"Open git-diff failed\");\n-\t} else  {\n-\t\tdie_error('404 Not Found', \"Missing one of the blob diff parameters\")\n-\t\t\tunless %diffinfo;\n+\t# fake git-diff-tree raw output\n+\t$diffinfo{'from_mode'} = $diffinfo{'to_mode'} = \"blob\";\n+\t$diffinfo{'from_id'} = $hash_parent;\n+\t$diffinfo{'to_id'}   = $hash;\n+\tif (defined $file_name) {\n+\t\t$diffinfo{'status'} = '2';\n+\t\t$diffinfo{'from_file'} = $file_parent;\n+\t\t$diffinfo{'to_file'}   = $file_name;\n+\t} else { # no filename given\n+\t\t$diffinfo{'status'} = '2';\n+\t\t$diffinfo{'from_file'} = $hash_parent;\n+\t\t$diffinfo{'to_file'}   = $hash;\n \t}\n \n+\t# open patch output\n+\topen $fd, \"-|\", git_cmd(), \"diff\", @diff_opts, '-p', \"--full-index\",\n+\t($format eq 'html' ? \"--raw\" : ()), $from, $to, \"--\"\n+\t\tor die_error(undef, \"Open git-diff failed\");\n+\n \t# header\n \tif ($format eq 'html') {\n \t\tmy $formats_nav =\n@@ -4771,11 +4728,12 @@ sub git_blobdiff {\n \t\t}\n \n \t} elsif ($format eq 'plain') {\n+\t\tmy $patch_file_name = $file_name || $hash;\n \t\tprint $cgi->header(\n \t\t\t-type => 'text/plain',\n \t\t\t-charset => 'utf-8',\n \t\t\t-expires => $expires,\n-\t\t\t-content_disposition => 'inline; filename=\"' . \"$file_name\" . '.patch\"');\n+\t\t\t-content_disposition => 'inline; filename=\"' . \"$patch_file_name\" . '.patch\"');\n \n \t\tprint \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n \n-- \n1.5.3.rc7.849.g2f5f\n"},{"id":"52203","messageId":"11887443693783-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"9745","inReplyTo":"11887443692839-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 2/5] gitweb: support filename prefix in git_patchset_body/git_difftree_body","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-02T14:46:05Z","receivedAt":"2007-09-02T14:46:05Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"git_treediff supports comparing subdirectories. As the output of\ngit-difftree is missing the path to the compared directories,\nthe links in the output would be wrong.\n\nThe patch adds two new parameters to add the missing path prefix.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n gitweb/gitweb.perl |   88 +++++++++++++++++++++++++++++----------------------\n 1 files changed, 50 insertions(+), 38 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 05bfb26..5f67d73 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -1173,10 +1173,10 @@ sub format_diff_from_to_header {\n \t\t\t\t        $cgi->a({-href=>href(action=>\"blobdiff\",\n \t\t\t\t                             hash_parent=>$diffinfo->{'from_id'}[$i],\n \t\t\t\t                             hash_parent_base=>$parents[$i],\n-\t\t\t\t                             file_parent=>$from->{'file'}[$i],\n+\t\t\t\t                             file_parent=>$diffinfo->{'from_prefix'}.$from->{'file'}[$i],\n \t\t\t\t                             hash=>$diffinfo->{'to_id'},\n \t\t\t\t                             hash_base=>$hash,\n-\t\t\t\t                             file_name=>$to->{'file'}),\n+\t\t\t\t                             file_name=>$diffinfo->{'to_prefix'}.$to->{'file'}),\n \t\t\t\t                 -class=>\"path\",\n \t\t\t\t                 -title=>\"diff\" . ($i+1)},\n \t\t\t\t                $i+1) .\n@@ -1219,7 +1219,7 @@ sub format_diff_cc_simplified {\n \t\t$result .= $cgi->a({-href => href(action=>\"blob\",\n \t\t                                  hash_base=>$hash,\n \t\t                                  hash=>$diffinfo->{'to_id'},\n-\t\t                                  file_name=>$diffinfo->{'to_file'}),\n+\t\t                                  file_name=>$diffinfo->{'to_prefix'}.$diffinfo->{'to_file'}),\n \t\t                    -class => \"path\"},\n \t\t                   esc_path($diffinfo->{'to_file'}));\n \t} else {\n@@ -2027,7 +2027,7 @@ sub parse_from_to_diffinfo {\n \t\t\t\t$from->{'href'}[$i] = href(action=>\"blob\",\n \t\t\t\t                           hash_base=>$parents[$i],\n \t\t\t\t                           hash=>$diffinfo->{'from_id'}[$i],\n-\t\t\t\t                           file_name=>$from->{'file'}[$i]);\n+\t\t\t\t                           file_name=>$diffinfo->{'from_prefix'}.$from->{'file'}[$i]);\n \t\t\t} else {\n \t\t\t\t$from->{'href'}[$i] = undef;\n \t\t\t}\n@@ -2037,7 +2037,7 @@ sub parse_from_to_diffinfo {\n \t\tif ($diffinfo->{'status'} ne \"A\") { # not new (added) file\n \t\t\t$from->{'href'} = href(action=>\"blob\", hash_base=>$hash_parent,\n \t\t\t                       hash=>$diffinfo->{'from_id'},\n-\t\t\t                       file_name=>$from->{'file'});\n+\t\t\t                       file_name=>$diffinfo->{'from_prefix'}.$from->{'file'});\n \t\t} else {\n \t\t\tdelete $from->{'href'};\n \t\t}\n@@ -2047,7 +2047,7 @@ sub parse_from_to_diffinfo {\n \tif (!is_deleted($diffinfo)) { # file exists in result\n \t\t$to->{'href'} = href(action=>\"blob\", hash_base=>$hash,\n \t\t                     hash=>$diffinfo->{'to_id'},\n-\t\t                     file_name=>$to->{'file'});\n+\t\t                     file_name=>$diffinfo->{'to_prefix'}.$to->{'file'});\n \t} else {\n \t\tdelete $to->{'href'};\n \t}\n@@ -2795,9 +2795,13 @@ sub is_deleted {\n }\n \n sub git_difftree_body {\n-\tmy ($difftree, $hash, @parents) = @_;\n+\tmy ($difftree, $from_prefix, $to_prefix, $hash, @parents) = @_;\n \tmy ($parent) = $parents[0];\n \tmy ($have_blame) = gitweb_check_feature('blame');\n+\n+\t$from_prefix = !defined $from_prefix ? '' : $from_prefix.'/';\n+\t$to_prefix   = !defined $to_prefix   ? '' : $to_prefix . '/';\n+\n \tprint \"<div class=\\\"list_head\\\">\\n\";\n \tif ($#{$difftree} > 10) {\n \t\tprint(($#{$difftree} + 1) . \" files changed:\\n\");\n@@ -2854,7 +2858,7 @@ sub git_difftree_body {\n \t\t\t\t# file exists in the result (child) commit\n \t\t\t\tprint \"<td>\" .\n \t\t\t\t      $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t\t                             file_name=>$diff->{'to_file'},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash),\n \t\t\t\t              -class => \"list\"}, esc_path($diff->{'to_file'})) .\n \t\t\t\t      \"</td>\\n\";\n@@ -2891,7 +2895,7 @@ sub git_difftree_body {\n \t\t\t\t\t      $cgi->a({-href => href(action=>\"blob\",\n \t\t\t\t\t                             hash_base=>$hash,\n \t\t\t\t\t                             hash=>$from_hash,\n-\t\t\t\t\t                             file_name=>$from_path)},\n+\t\t\t\t\t                             file_name=>$from_prefix.$from_path)},\n \t\t\t\t\t              \"blob\" . ($i+1)) .\n \t\t\t\t\t      \" | </td>\\n\";\n \t\t\t\t} else {\n@@ -2905,8 +2909,8 @@ sub git_difftree_body {\n \t\t\t\t\t                             hash_parent=>$from_hash,\n \t\t\t\t\t                             hash_base=>$hash,\n \t\t\t\t\t                             hash_parent_base=>$hash_parent,\n-\t\t\t\t\t                             file_name=>$diff->{'to_file'},\n-\t\t\t\t\t                             file_parent=>$from_path)},\n+\t\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n+\t\t\t\t\t                             file_parent=>$from_prefix.$from_path)},\n \t\t\t\t\t              \"diff\" . ($i+1)) .\n \t\t\t\t\t      \" | </td>\\n\";\n \t\t\t\t}\n@@ -2916,14 +2920,14 @@ sub git_difftree_body {\n \t\t\tif ($not_deleted) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blob\",\n \t\t\t\t                             hash=>$diff->{'to_id'},\n-\t\t\t\t                             file_name=>$diff->{'to_file'},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash)},\n \t\t\t\t              \"blob\");\n \t\t\t\tprint \" | \" if ($has_history);\n \t\t\t}\n \t\t\tif ($has_history) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"history\",\n-\t\t\t\t                             file_name=>$diff->{'to_file'},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash)},\n \t\t\t\t              \"history\");\n \t\t\t}\n@@ -2957,7 +2961,7 @@ sub git_difftree_body {\n \t\t\t$mode_chng   .= \"]</span>\";\n \t\t\tprint \"<td>\";\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'}),\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chng</td>\\n\";\n@@ -2969,7 +2973,7 @@ sub git_difftree_body {\n \t\t\t\tprint \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'})},\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t              \"blob\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -2977,7 +2981,7 @@ sub git_difftree_body {\n \t\t\tmy $mode_chng = \"<span class=\\\"file_status deleted\\\">[deleted $from_file_type]</span>\";\n \t\t\tprint \"<td>\";\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'from_id'},\n-\t\t\t                             hash_base=>$parent, file_name=>$diff->{'file'}),\n+\t\t\t                             hash_base=>$parent, file_name=>$from_prefix.$diff->{'file'}),\n \t\t\t               -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chng</td>\\n\";\n@@ -2989,15 +2993,15 @@ sub git_difftree_body {\n \t\t\t\tprint \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'from_id'},\n-\t\t\t                             hash_base=>$parent, file_name=>$diff->{'file'})},\n+\t\t\t                             hash_base=>$parent, file_name=>$from_prefix.$diff->{'file'})},\n \t\t\t              \"blob\") . \" | \";\n \t\t\tif ($have_blame) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blame\", hash_base=>$parent,\n-\t\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t\t                             file_name=>$from_prefix.$diff->{'file'})},\n \t\t\t\t              \"blame\") . \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"history\", hash_base=>$parent,\n-\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t                             file_name=>$from_prefix.$diff->{'file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -3019,7 +3023,7 @@ sub git_difftree_body {\n \t\t\t}\n \t\t\tprint \"<td>\";\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'}),\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chnge</td>\\n\";\n@@ -3034,20 +3038,21 @@ sub git_difftree_body {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blobdiff\",\n \t\t\t\t                             hash=>$diff->{'to_id'}, hash_parent=>$diff->{'from_id'},\n \t\t\t\t                             hash_base=>$hash, hash_parent_base=>$parent,\n-\t\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'file'},\n+\t\t\t\t                             file_parent=>$from_prefix.$diff->{'file'})},\n \t\t\t\t              \"diff\") .\n \t\t\t\t      \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'})},\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t               \"blob\") . \" | \";\n \t\t\tif ($have_blame) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blame\", hash_base=>$hash,\n-\t\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t\t              \"blame\") . \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"history\", hash_base=>$hash,\n-\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t                             file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -3061,11 +3066,11 @@ sub git_difftree_body {\n \t\t\t}\n \t\t\tprint \"<td>\" .\n \t\t\t      $cgi->a({-href => href(action=>\"blob\", hash_base=>$hash,\n-\t\t\t                             hash=>$diff->{'to_id'}, file_name=>$diff->{'to_file'}),\n+\t\t\t                             hash=>$diff->{'to_id'}, file_name=>$to_prefix.$diff->{'to_file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'to_file'})) . \"</td>\\n\" .\n \t\t\t      \"<td><span class=\\\"file_status $nstatus\\\">[$nstatus from \" .\n \t\t\t      $cgi->a({-href => href(action=>\"blob\", hash_base=>$parent,\n-\t\t\t                             hash=>$diff->{'from_id'}, file_name=>$diff->{'from_file'}),\n+\t\t\t                             hash=>$diff->{'from_id'}, file_name=>$from_prefix.$diff->{'from_file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'from_file'})) .\n \t\t\t      \" with \" . (int $diff->{'similarity'}) . \"% similarity$mode_chng]</span></td>\\n\" .\n \t\t\t      \"<td class=\\\"link\\\">\";\n@@ -3079,20 +3084,20 @@ sub git_difftree_body {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blobdiff\",\n \t\t\t\t                             hash=>$diff->{'to_id'}, hash_parent=>$diff->{'from_id'},\n \t\t\t\t                             hash_base=>$hash, hash_parent_base=>$parent,\n-\t\t\t\t                             file_name=>$diff->{'to_file'}, file_parent=>$diff->{'from_file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'}, file_parent=>$from_prefix.$diff->{'from_file'})},\n \t\t\t\t              \"diff\") .\n \t\t\t\t      \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$parent, file_name=>$diff->{'to_file'})},\n+\t\t\t                             hash_base=>$parent, file_name=>$to_prefix.$diff->{'to_file'})},\n \t\t\t              \"blob\") . \" | \";\n \t\t\tif ($have_blame) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blame\", hash_base=>$hash,\n-\t\t\t\t                             file_name=>$diff->{'to_file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'})},\n \t\t\t\t              \"blame\") . \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"history\", hash_base=>$hash,\n-\t\t\t                            file_name=>$diff->{'to_file'})},\n+\t\t\t                            file_name=>$to_prefix.$diff->{'to_file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -3104,7 +3109,7 @@ sub git_difftree_body {\n }\n \n sub git_patchset_body {\n-\tmy ($fd, $difftree, $hash, @hash_parents) = @_;\n+\tmy ($fd, $difftree, $from_prefix, $to_prefix, $hash, @hash_parents) = @_;\n \tmy ($hash_parent) = $hash_parents[0];\n \n \tmy $patch_idx = 0;\n@@ -3113,6 +3118,9 @@ sub git_patchset_body {\n \tmy $diffinfo;\n \tmy (%from, %to);\n \n+\t$from_prefix = !defined $from_prefix ? '' : $from_prefix.'/';\n+\t$to_prefix   = !defined $to_prefix   ? '' : $to_prefix . '/';\n+\n \tprint \"<div class=\\\"patchset\\\">\\n\";\n \n \t# skip to first patch\n@@ -3160,6 +3168,8 @@ sub git_patchset_body {\n \t\t    $diffinfo->{'to_id'} eq $to_id) {\n \t\t\t# this is continuation of a split patch\n \t\t\tprint \"<div class=\\\"patch cont\\\">\\n\";\n+\t\t\t$diffinfo->{'from_prefix'} = $from_prefix;\n+\t\t\t$diffinfo->{'to_prefix'} = $to_prefix;\n \t\t} else {\n \t\t\t# advance raw git-diff output if needed\n \t\t\t$patch_idx++ if defined $diffinfo;\n@@ -3191,6 +3201,8 @@ sub git_patchset_body {\n \t\t\t\t}\n \t\t\t} until (!defined $to_name || $to_name eq $diffinfo->{'to_file'} ||\n \t\t\t         $patch_idx > $#$difftree);\n+\t\t\t$diffinfo->{'from_prefix'} = $from_prefix;\n+\t\t\t$diffinfo->{'to_prefix'} = $to_prefix;\n \t\t\t# modifies %from, %to hashes\n \t\t\tparse_from_to_diffinfo($diffinfo, \\%from, \\%to, @hash_parents);\n \t\t\tif ($diffinfo->{'nparents'}) {\n@@ -3205,7 +3217,7 @@ sub git_patchset_body {\n \t\t\t\t\t\t$from{'href'}[$i] = href(action=>\"blob\",\n \t\t\t\t\t\t                         hash_base=>$hash_parents[$i],\n \t\t\t\t\t\t                         hash=>$diffinfo->{'from_id'}[$i],\n-\t\t\t\t\t\t                         file_name=>$from{'file'}[$i]);\n+\t\t\t\t\t\t                         file_name=>$from_prefix.$from{'file'}[$i]);\n \t\t\t\t\t} else {\n \t\t\t\t\t\t$from{'href'}[$i] = undef;\n \t\t\t\t\t}\n@@ -3215,7 +3227,7 @@ sub git_patchset_body {\n \t\t\t\tif ($diffinfo->{'status'} ne \"A\") { # not new (added) file\n \t\t\t\t\t$from{'href'} = href(action=>\"blob\", hash_base=>$hash_parent,\n \t\t\t\t\t                     hash=>$diffinfo->{'from_id'},\n-\t\t\t\t\t                     file_name=>$from{'file'});\n+\t\t\t\t\t                     file_name=>$from_prefix.$from{'file'});\n \t\t\t\t} else {\n \t\t\t\t\tdelete $from{'href'};\n \t\t\t\t}\n@@ -3225,7 +3237,7 @@ sub git_patchset_body {\n \t\t\tif (!is_deleted($diffinfo)) { # file exists in result\n \t\t\t\t$to{'href'} = href(action=>\"blob\", hash_base=>$hash,\n \t\t\t\t                   hash=>$diffinfo->{'to_id'},\n-\t\t\t\t                   file_name=>$to{'file'});\n+\t\t\t\t                   file_name=>$to_prefix.$to{'file'});\n \t\t\t} else {\n \t\t\t\tdelete $to{'href'};\n \t\t\t}\n@@ -4587,7 +4599,7 @@ sub git_commit {\n \tgit_print_log($co{'comment'});\n \tprint \"</div>\\n\";\n \n-\tgit_difftree_body(\\@difftree, $hash, @$parents);\n+\tgit_difftree_body(\\@difftree, undef, undef, $hash, @$parents);\n \n \tgit_footer_html();\n }\n@@ -4745,7 +4757,7 @@ sub git_blobdiff {\n \tif ($format eq 'html') {\n \t\tprint \"<div class=\\\"page_body\\\">\\n\";\n \n-\t\tgit_patchset_body($fd, [ \\%diffinfo ], $hash_base, $hash_parent_base);\n+\t\tgit_patchset_body($fd, [ \\%diffinfo ], undef, undef, $hash_base, $hash_parent_base);\n \t\tclose $fd;\n \n \t\tprint \"</div>\\n\"; # class=\"page_body\"\n@@ -4928,11 +4940,11 @@ TEXT\n \tif ($format eq 'html') {\n \t\tmy $use_parents = !defined $hash_parent ||\n \t\t\t$hash_parent eq '-c' || $hash_parent eq '--cc';\n-\t\tgit_difftree_body(\\@difftree, $hash,\n+\t\tgit_difftree_body(\\@difftree, undef, undef, $hash,\n \t\t                  $use_parents ? @{$co{'parents'}} : $hash_parent);\n \t\tprint \"<br/>\\n\";\n \n-\t\tgit_patchset_body($fd, \\@difftree, $hash,\n+\t\tgit_patchset_body($fd, \\@difftree, undef, undef, $hash,\n \t\t                  $use_parents ? @{$co{'parents'}} : $hash_parent);\n \t\tclose $fd;\n \t\tprint \"</div>\\n\"; # class=\"page_body\"\n-- \n1.5.3.rc7.849.g2f5f\n"},{"id":"52198","messageId":"11887443693173-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"9745","inReplyTo":"11887443693783-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 3/5] gitweb: Add treediff view","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-02T14:46:06Z","receivedAt":"2007-09-02T14:46:06Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"git_treediff supports comparing different trees. A tree can be specified\neither as hash or as base hash and filename.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n gitweb/gitweb.perl |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 116 insertions(+), 0 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 5f67d73..4081f51 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -549,6 +549,8 @@ my %actions = (\n \t\"tag\" => \\&git_tag,\n \t\"tags\" => \\&git_tags,\n \t\"tree\" => \\&git_tree,\n+\t\"treediff\" => \\&git_treediff,\n+\t\"treediff_plain\" => \\&git_treediff_plain,\n \t\"snapshot\" => \\&git_snapshot,\n \t\"object\" => \\&git_object,\n \t# those below don't need $project\n@@ -4962,6 +4964,120 @@ sub git_commitdiff_plain {\n \tgit_commitdiff('plain');\n }\n \n+sub git_treediff {\n+\tmy $format = shift || 'html';\n+\tmy $expires = '+1d';\n+\n+\t# non-textual hash id's can be cached\n+\tif (defined $hash && $hash !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent && $hash_parent !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_base && $hash_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent_base && $hash_parent_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t}\n+\n+\t# we need to prepare $formats_nav before any parameter munging\n+\tmy $formats_nav;\n+\tif ($format eq 'html') {\n+\t\t$formats_nav =\n+\t\t\t$cgi->a({-href => href(action=>\"treediff_plain\",\n+\t\t\t\t\t\t\t\t   hash=>$hash, hash_parent=>$hash_parent,\n+\t\t\t\t\t\t\t\t   hash_base=>$hash_base, hash_parent_base=>$hash_parent_base,\n+\t\t\t\t\t\t\t\t   file_name=>$file_name, file_parent=>$file_parent)},\n+\t\t\t\t\t\"raw\");\n+\t}\n+\n+\tif (!defined $hash) {\n+\t\tif (!defined $hash_base) {\n+\t\t\tdie_error(undef,'tree parameter missing');\n+\t\t}\n+\t\t$hash = $hash_base;\n+\t\t$hash .= \":\".$file_name if (defined $file_name);\n+\t}\n+\t\n+\tif (!defined $hash_parent) {\n+\t\tif (!defined $hash_parent_base) {\n+\t\t\tdie_error(undef,'tree parameter missing');\n+\t\t}\n+\t\t$hash_parent = $hash_parent_base;\n+\t\t$hash_parent .= \":\".$file_parent if (defined $file_parent);\n+\t}\n+\n+\t# read treediff\n+\tmy $fd;\n+\tmy @difftree;\n+\tif ($format eq 'html') {\n+\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n+\t\t\"--no-commit-id\", \"--patch-with-raw\", \"--full-index\",\n+\t\t$hash_parent, $hash, \"--\"\n+\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\t\t\n+\t\twhile (my $line = <$fd>) {\n+\t\t\tchomp $line;\n+\t\t\t# empty line ends raw part of diff-tree output\n+\t\t\tlast unless $line;\n+\t\t\tpush @difftree, $line;\n+\t\t}\n+\t\t\n+\t} elsif ($format eq 'plain') {\n+\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n+\t\t'-p', $hash_parent, $hash, \"--\"\n+\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\t\t\n+\t} else {\n+\t\tdie_error(undef, \"Unknown treediff format\");\n+\t}\n+\n+\t# write header\n+\tif ($format eq 'html') {\n+\t\tgit_header_html(undef, $expires);\n+\t\tif (defined $hash_base && (my %co = parse_commit($hash_base))) {\n+\t\t\tgit_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);\n+\t\t\tgit_print_header_div('commit', esc_html($co{'title'}), $hash_base);\n+\t\t} else {\n+\t\t\tprint \"<div class=\\\"page_nav\\\"><br/>$formats_nav<br/></div>\\n\";\n+\t\t\tprint \"<div class=\\\"title\\\">$hash vs $hash_parent</div>\\n\";\n+\t\t}\n+\t\tprint \"<div class=\\\"page_body\\\">\\n\";\n+\t\t\n+\t} elsif ($format eq 'plain') {\n+\t\tmy $filename = basename($project) . \"-$hash-$hash_parent.patch\";\n+\t\t\n+\t\tprint $cgi->header(\n+\t\t\t\t\t\t   -type => 'text/plain',\n+\t\t\t\t\t\t   -charset => 'utf-8',\n+\t\t\t\t\t\t   -expires => $expires,\n+\t\t\t\t\t\t   -content_disposition => 'inline; filename=\"' . \"$filename\" . '\"');\n+\t\t\n+\t\tprint \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n+\t\tprint \"---\\n\\n\";\n+\t}\n+\t\n+\t# write patch\n+\tif ($format eq 'html') {\n+\t\tgit_difftree_body(\\@difftree, $file_parent, $file_name, $hash_base, $hash_parent_base);\n+\t\tprint \"<br/>\\n\";\n+\n+\t\tgit_patchset_body($fd, \\@difftree, $file_parent, $file_name, $hash_base, $hash_parent_base);\n+\t\tclose $fd;\n+\t\tprint \"</div>\\n\"; # class=\"page_body\"\n+\t\tgit_footer_html();\n+\n+\t} elsif ($format eq 'plain') {\n+\t\tlocal $/ = undef;\n+\t\tprint <$fd>;\n+\t\tclose $fd\n+\t\t\tor print \"Reading git-diff-tree failed\\n\";\n+\t}\n+}\n+\n+sub git_treediff_plain {\n+\tgit_treediff('plain');\n+}\n+\n sub git_history {\n \tif (!defined $hash_base) {\n \t\t$hash_base = git_get_head_hash($project);\n-- \n1.5.3.rc7.849.g2f5f\n"},{"id":"52202","messageId":"11887443693825-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"9745","inReplyTo":"11887443693173-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 4/5] gitweb: Selecting diffs in JavaScript","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-02T14:46:07Z","receivedAt":"2007-09-02T14:46:07Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"The adds support for selecting arbitrary diffs, if the client browser supports\nJavaScript.\n\nIt is no possible to hide/show all diff links.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n Makefile           |    6 +-\n git-instaweb.sh    |    7 +\n gitweb/gitweb.js   |  360 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n gitweb/gitweb.perl |   11 ++\n 4 files changed, 383 insertions(+), 1 deletions(-)\n create mode 100644 gitweb/gitweb.js\n\ndiff --git a/Makefile b/Makefile\nindex 2decdfb..1582dfa 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -168,6 +168,7 @@ GITWEB_HOMETEXT = indextext.html\n GITWEB_CSS = gitweb.css\n GITWEB_LOGO = git-logo.png\n GITWEB_FAVICON = git-favicon.png\n+GITWEB_JS = gitweb.js\n GITWEB_SITE_HEADER =\n GITWEB_SITE_FOOTER =\n \n@@ -817,13 +818,14 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl\n \t    -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \\\n \t    -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \\\n \t    -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \\\n+\t    -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \\\n \t    -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \\\n \t    -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \\\n \t    $< >$@+ && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\n \n-git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css\n+git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js\n \t$(QUIET_GEN)$(RM) $@ $@+ && \\\n \tsed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n \t    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n@@ -832,6 +834,8 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css\n \t    -e '/@@GITWEB_CGI@@/d' \\\n \t    -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \\\n \t    -e '/@@GITWEB_CSS@@/d' \\\n+\t    -e '/@@GITWEB_JS@@/r gitweb/gitweb.js' \\\n+\t    -e '/@@GITWEB_JS@@/d' \\\n \t    $@.sh > $@+ && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\ndiff --git a/git-instaweb.sh b/git-instaweb.sh\nindex b79c6b6..960486e 100755\n--- a/git-instaweb.sh\n+++ b/git-instaweb.sh\n@@ -227,8 +227,15 @@ gitweb_css () {\n EOFGITWEB\n }\n \n+gitweb_js () {\n+\tcat > \"$1\" <<\\EOFGITWEB\n+@@GITWEB_JS@@\n+EOFGITWEB\n+}\n+\n gitweb_cgi $GIT_DIR/gitweb/gitweb.cgi\n gitweb_css $GIT_DIR/gitweb/gitweb.css\n+gitweb_js $GIT_DIR/gitweb/gitweb.js\n \n case \"$httpd\" in\n *lighttpd*)\ndiff --git a/gitweb/gitweb.js b/gitweb/gitweb.js\nnew file mode 100644\nindex 0000000..fd4178a\n--- /dev/null\n+++ b/gitweb/gitweb.js\n@@ -0,0 +1,360 @@\n+/* Javascript functions for gitweb\n+\n+  (C) 2007 Martin Koegler <mkoegler@auto.tuwien.ac.at>\n+\n+  This file is licensed under the GPL v2, or (at your option) any later version.\n+*/\n+\n+function getCookie (name)\n+{\n+  var name = name + \"=\";\n+  var c = document.cookie;\n+  var p = c.indexOf (name);\n+  if (p == -1)\n+    return null;\n+  c = c.substr (p + name.length, c.length);\n+  p = c.indexOf (\";\");\n+  if (p == -1)\n+    return c;\n+  else\n+    return c.substr (0, p);\n+}\n+\n+function insertAfter (elem, node)\n+{\n+  if (node.nextSibling)\n+    node.parentNode.insertBefore (elem, node.nextSibling);\n+  else\n+    node.parentNode.appendChild (elem);\n+}\n+\n+function createLink (href, linktext)\n+{\n+  var l = document.createElement (\"a\");\n+  l.appendChild (document.createTextNode (linktext));\n+  l.href = href;\n+  return l;\n+}\n+\n+function createLinkGroup (href1, basetxt, href2, difftxt)\n+{\n+  var l = document.createElement (\"span\");\n+  l.className = 'difflinks';\n+  l.appendChild (document.createTextNode (\" (\"));\n+  l.appendChild (createLink (href1, basetxt));\n+  l.appendChild (document.createTextNode (\" | \"));\n+  l.appendChild (createLink (href2, difftxt));\n+  l.appendChild (document.createTextNode (\") \"));\n+  return l;\n+}\n+\n+function GitRef ()\n+{\n+  this.t = null;\n+  this.h = null;\n+  this.hb = null;\n+  this.f = null;\n+  this.p = null;\n+  this.ToRef = ToRef;\n+}\n+\n+function ToRef ()\n+{\n+  var parts = new Array ();\n+  if (this.f)\n+    parts.push (\"f=\" + this.f);\n+  if (this.h)\n+    parts.push (\"h=\" + this.h);\n+  if (this.hb)\n+    parts.push (\"hb=\" + this.hb);\n+  if (this.t)\n+    parts.push (\"t=\" + this.t);\n+  if (this.p)\n+    parts.push (\"p=\" + this.p);\n+  return parts.join (\"@\");\n+}\n+\n+function splitGitRef (ref)\n+{\n+  var parts = ref.split (\"@\");\n+  var res = new GitRef ();\n+  var i;\n+  for (i = 0; i < parts.length; i++)\n+    {\n+      var p = parts[i].split (\"=\");\n+      res[p[0]] = p[1];\n+    }\n+  return res;\n+}\n+\n+function GitURL (base)\n+{\n+  this.base = base;\n+  this.p = null;\n+  this.a = null;\n+  this.f = null;\n+  this.fp = null;\n+  this.h = null;\n+  this.hp = null;\n+  this.hb = null;\n+  this.hpb = null;\n+  this.pg = null;\n+  this.o = null;\n+  this.s = null;\n+  this.st = null;\n+  this.ToURL = ToURL;\n+  this.ToRef = UrlToRef;\n+  this.ToDUrl = ToDUrl;\n+}\n+\n+function ToURL ()\n+{\n+  var parts = new Array ();\n+  if (this.p)\n+    parts.push (\"p=\" + this.p);\n+  if (this.a)\n+    parts.push (\"a=\" + this.a);\n+  if (this.f)\n+    parts.push (\"f=\" + this.f);\n+  if (this.fp)\n+    parts.push (\"fp=\" + this.fp);\n+  if (this.h)\n+    parts.push (\"h=\" + this.h);\n+  if (this.hp)\n+    parts.push (\"hp=\" + this.hp);\n+  if (this.hb)\n+    parts.push (\"hb=\" + this.hb);\n+  if (this.hpb)\n+    parts.push (\"hpb=\" + this.hpb);\n+  if (this.o)\n+    parts.push (\"o=\" + this.o);\n+  if (this.s)\n+    parts.push (\"s=\" + this.s);\n+  if (this.st)\n+    parts.push (\"st=\" + this.st);\n+  return this.base + \"?\" + parts.join (\";\");\n+}\n+\n+function UrlToRef (type)\n+{\n+  var res = new GitRef;\n+  res.f = this.f;\n+  res.h = this.h;\n+  res.hb = this.hb;\n+  res.t = type;\n+  res.p = this.p;\n+  return res.ToRef ();\n+}\n+\n+function ToDUrl (type)\n+{\n+  var res = new GitURL (this.base);\n+  res.f = this.f;\n+  res.h = this.h;\n+  res.hb = this.hb;\n+  res.p = this.p;\n+  res.a = type;\n+  return res.ToURL ();\n+}\n+\n+function splitGitURL (url)\n+{\n+  var Urls = url.split (\"?\");\n+  var res = new GitURL (Urls[0]);\n+  if (Urls.length > 1)\n+    {\n+      var parts = Urls[1].split (\";\");\n+      var i;\n+      for (i = 0; i < parts.length; i++)\n+\t{\n+\t  var p = parts[i].split (\"=\");\n+\t  res[p[0]] = p[1];\n+\t}\n+    }\n+  return res;\n+}\n+\n+function base (ref)\n+{\n+  document.cookie = \"basename=\" + ref;\n+}\n+\n+function diff (url)\n+{\n+  var c = getCookie (\"basename\");\n+  if (!c)\n+    {\n+      alert (\"no diff base selected\");\n+      return;\n+    }\n+  c = splitGitRef (c);\n+  url = splitGitURL (url);\n+\n+  if (c.p != url.p)\n+    {\n+      alert (\"base object in an other repository\");\n+      return;\n+    }\n+\n+  if (c.t == 'commit' && url.a == 'commit')\n+    {\n+      url.a = 'commitdiff';\n+      if (!c.h || !url.h)\n+\t{\n+\t  alert (\"commit diff not possible\");\n+\t  return;\n+\t}\n+      url.hb = null;\n+      url.f = null;\n+      url.hp = c.h;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'blob' && url.a == 'blob')\n+    {\n+      url.a = 'blobdiff';\n+      url.hp = c.h;\n+      url.hpb = c.hb;\n+      url.fp = c.f;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'tree' && url.a == 'tree')\n+    {\n+      url.a = 'treediff';\n+      url.hpb = c.hb;\n+      url.hp = c.h;\n+      url.fp = c.f;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'commit' && url.a == 'tree')\n+    {\n+      url.a = 'treediff';\n+      url.hpb = c.h;\n+      url.hp = null;\n+      url.fp = null;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'tree' && url.a == 'commit')\n+    {\n+      url.a = 'treediff';\n+      url.hpb = c.hb;\n+      url.hp = c.h;\n+      url.fp = c.f;\n+      url.hb = url.h;\n+      url.h = null;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  alert (\"diff not possible\");\n+}\n+\n+function GitAddLinks ()\n+{\n+  var links = document.getElementsByTagName (\"a\");\n+  var i;\n+\n+  for (i = 0; i < links.length; i++)\n+    {\n+      var link = links[i];\n+      var url = splitGitURL (link.href);\n+      if (link.innerHTML == 'commit' || link.innerHTML == 'tag')\n+\t{\n+\t  if (!url.h)\n+\t    continue;\n+\t  var l =\n+\t    createLinkGroup (\"javascript:base('\" + url.ToRef ('commit') +\n+\t\t\t     \"')\", \"base\",\n+\t\t\t     \"javascript:diff('\" + url.ToDUrl ('commit') +\n+\t\t\t     \"')\", \"diff\");\n+\t  insertAfter (l, link);\n+\t}\n+      if (link.innerHTML == 'blob')\n+\t{\n+\t  if (!url.h && !(url.hb && url.f))\n+\t    continue;\n+\t  var l =\n+\t    createLinkGroup (\"javascript:base('\" + url.ToRef ('blob') + \"')\",\n+\t\t\t     \"base\",\n+\t\t\t     \"javascript:diff('\" + url.ToDUrl ('blob') + \"')\",\n+\t\t\t     \"diff\");\n+\t  insertAfter (l, link);\n+\t}\n+      if (link.innerHTML == 'tree')\n+\t{\n+\t  if (!url.h && !(url.hb && url.f))\n+\t    continue;\n+\t  var l =\n+\t    createLinkGroup (\"javascript:base('\" + url.ToRef ('tree') + \"')\",\n+\t\t\t     \"base\",\n+\t\t\t     \"javascript:diff('\" + url.ToDUrl ('tree') + \"')\",\n+\t\t\t     \"diff\");\n+\t  insertAfter (l, link);\n+\t}\n+    }\n+}\n+\n+function ShowHideLinks (action)\n+{\n+  var tags = document.getElementsByTagName (\"span\");\n+\n+  for (i = 0; i < tags.length; i++)\n+    {\n+      var tag = tags[i];\n+      if (tag.className == 'difflinks')\n+\t{\n+\t  if (action)\n+\t    tag.style.display = 'inline';\n+\t  else\n+\t    tag.style.display = 'none';\n+\t}\n+    }\n+\n+}\n+\n+var LinkState=-1;\n+var saveonload;\n+\n+function GitShowLinks ()\n+{\n+  if (LinkState == -1)\n+    {\n+      GitAddLinks();\n+      LinkState = 1;\n+      document.cookie = \"showdiff=1\";\n+      document.getElementById ('difflinks').innerHTML = 'hide difflinks';\n+    }\t\n+  else if (LinkState == 1)\n+    {\n+      ShowHideLinks (false);\n+      LinkState = 0;\n+      document.cookie = \"showdiff=0\";\n+      document.getElementById ('difflinks').innerHTML = 'show difflinks';\n+    }\n+  else\n+    {\n+      ShowHideLinks (true);\n+      LinkState = 1;\n+      document.cookie = \"showdiff=1\";\n+      document.getElementById ('difflinks').innerHTML = 'hide difflinks';\n+    }\n+}\n+\n+function GitAddLinkElement ()\n+{\n+    document.getElementById ('difflinkdiv').innerHTML = \n+      ' | <a id=\"difflinks\" href=\"javascript:GitShowLinks()\">show difflinks</a>';\n+    var show = getCookie ('showdiff');\n+    if (show == '1')\n+      {\n+\tsaveonload = window.onload;\n+\twindow.onload = function ()\n+\t  {\n+\t    if (saveonload)\n+\t       saveonload();\n+\t    GitShowLinks();\n+\t  }\n+      }\n+}\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 4081f51..2531133 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -61,6 +61,8 @@ our $stylesheet = undef;\n our $logo = \"++GITWEB_LOGO++\";\n # URI of GIT favicon, assumed to be image/png type\n our $favicon = \"++GITWEB_FAVICON++\";\n+# URI of gitweb.js\n+our $gitwebjs = \"++GITWEB_JS++\";\n \n # URI and label (title) of GIT logo link\n #our $logo_url = \"http://www.kernel.org/pub/software/scm/git/docs/\";\n@@ -2313,6 +2315,10 @@ EOF\n \t\tprint qq(<link rel=\"shortcut icon\" href=\"$favicon\" type=\"image/png\"/>\\n);\n \t}\n \n+\tif (defined $gitwebjs) {\n+\t\tprint qq(<script src=\"$gitwebjs\" type=\"text/javascript\"></script>\\n);\n+\t}\n+\n \tprint \"</head>\\n\" .\n \t      \"<body>\\n\";\n \n@@ -2449,6 +2455,11 @@ sub git_print_page_nav {\n \t\t map { $_ eq $current ?\n \t\t       $_ : $cgi->a({-href => href(%{$arg{$_}})}, \"$_\")\n \t\t } @navs);\n+\n+\tif (defined $gitwebjs) {\n+\t\tprint '<span id=\"difflinkdiv\"></span><script type=\"text/javascript\">GitAddLinkElement();</script>';\n+\t}\n+\n \tprint \"<br/>\\n$extra<br/>\\n\" .\n \t      \"</div>\\n\";\n }\n-- \n1.5.3.rc7.849.g2f5f\n"},{"id":"52199","messageId":"11887443694-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"9745","inReplyTo":"11887443693825-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 5/5] Show Difflinks in an other color","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-02T14:46:08Z","receivedAt":"2007-09-02T14:46:08Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"Suggested by Petr Baudis\n\nThe style for the links was randomly selected.\n\nNo sign-off, as somebody else should select a suiteable style.\n---\n gitweb/gitweb.css |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/gitweb/gitweb.css b/gitweb/gitweb.css\nindex 1b88879..ac15c0e 100644\n--- a/gitweb/gitweb.css\n+++ b/gitweb/gitweb.css\n@@ -499,3 +499,7 @@ span.match {\n div.binary {\n \tfont-style: italic;\n }\n+\n+span.difflinks a {\n+\tcolor: #ff0000;\n+}\n-- \n1.5.3.rc7.849.g2f5f\n"},{"id":"52284","messageId":"fbfjtl$7gh$1@sea.gmane.org","threadId":"9745","inReplyTo":"11887443682216-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"Re: [PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-09-03T00:19:05Z","receivedAt":"2007-09-03T00:19:05Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"[Cc: Martin Koegler <mkoegler@auto.tuwien.ac.at>,\n     Petr Baudis <pasky@suse.cz>, git@vger.kernel.org]\n\nMartin Koegler wrote:\n\n> Patch 4 now only generates the links, if they are enabled.\n> The header contains a new link to show/hide the links.\n> The state is remembered via a cookie across pages.\n\nI'd rather have patch adding cookie management (are they only JavaScript,\nor also server side?) as a separate patch.\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"52294","messageId":"20070903013330.GR1219@pasky.or.cz","threadId":"9745","inReplyTo":"fbfjtl$7gh$1@sea.gmane.org","subject":"Re: [PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2007-09-03T01:33:30Z","receivedAt":"2007-09-03T01:33:30Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Mon, Sep 03, 2007 at 02:19:05AM CEST, Jakub Narebski wrote:\n> [Cc: Martin Koegler <mkoegler@auto.tuwien.ac.at>,\n>      Petr Baudis <pasky@suse.cz>, git@vger.kernel.org]\n> \n> Martin Koegler wrote:\n> \n> > Patch 4 now only generates the links, if they are enabled.\n> > The header contains a new link to show/hide the links.\n> > The state is remembered via a cookie across pages.\n> \n> I'd rather have patch adding cookie management (are they only JavaScript,\n> or also server side?) as a separate patch.\n\nThis is purely in-Javascript thing, so I don't think a separate patch\nmakes much sense.\n\nTo hijack this post a bit, another patch in the queue (the incremental\nblame thingie) introduces blame.js. Do you think that we should keep the\n.js files separate, or instead have one big gitweb.js with everything?\nI'm inclined to the second possibility in order to reduce the number of\nrequests, but it comes at a price of slightly worse maintainability.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nEarly to rise and early to bed makes a male healthy and wealthy and dead.\n                -- James Thurber\n"},{"id":"52296","messageId":"7v1wdgo5x9.fsf@gitster.siamese.dyndns.org","threadId":"9745","inReplyTo":"20070903013330.GR1219@pasky.or.cz","subject":"Re: [PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-09-03T02:10:10Z","receivedAt":"2007-09-03T02:10:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> To hijack this post a bit, another patch in the queue (the incremental\n> blame thingie) introduces blame.js. Do you think that we should keep the\n> .js files separate, or instead have one big gitweb.js with everything?\n> I'm inclined to the second possibility in order to reduce the number of\n> requests, but it comes at a price of slightly worse maintainability.\n\nIs it a possibility to concatenate them at the installation\ntime, if a single huge file becomes a problem?\n"},{"id":"52335","messageId":"200709031023.42366.jnareb@gmail.com","threadId":"9745","inReplyTo":"20070903013330.GR1219@pasky.or.cz","subject":"Re: [PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-09-03T08:23:41Z","receivedAt":"2007-09-03T08:23:41Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Mon, 3 September 2007, Petr \"Pasky\" Baudis wrote:\n\n> To hijack this post a bit, another patch in the queue (the incremental\n> blame thingie) introduces blame.js. Do you think that we should keep the\n> .js files separate, or instead have one big gitweb.js with everything?\n> I'm inclined to the second possibility in order to reduce the number of\n> requests, but it comes at a price of slightly worse maintainability.\n\nOn the other hand if we have blame.js separate, we could load it\n(require it) only for the 'blame' view, it means only when needed.\n\ngitweb.js would contain JavaScript code used by all (or almost all)\nviews, then...\n\nI don't think gitweb.js would be as large as gitweb.perl, if we are\ntalking about maintability ;-)\n\n-- \nJakub Narebski\nPoland\n"},{"id":"52348","messageId":"tnxodgkuee7.fsf@arm.com","threadId":"9745","inReplyTo":"11887443682216-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"Re: [PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@arm.com","sentAt":"2007-09-03T12:22:56Z","receivedAt":"2007-09-03T12:22:56Z","isPatch":true,"sender":{"key":"catalin.marinas@arm.com","avatar":null},"body":"Martin Koegler <mkoegler@auto.tuwien.ac.at> wrote:\n> I develop the patches via StGit. If you think that I should publish them\n> in a different way, please tell me.\n\nYou could use 'stg mail' to send the patches and it makes each patch a\ndirect child of the main series description (PATCH 0/5) rather than a\nchild of the previous patch. It looks nicer with a threaded view.\n\n-- \nCatalin\n"},{"id":"52405","messageId":"20070904063151.GA17799@auto.tuwien.ac.at","threadId":"9745","inReplyTo":"200709031023.42366.jnareb@gmail.com","subject":"Re: [PATCH 0/5] gitweb: Support for arbitrary diffs","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-09-04T06:31:51Z","receivedAt":"2007-09-04T06:31:51Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"On Mon, Sep 03, 2007 at 10:23:41AM +0200, Jakub Narebski wrote:\n> On Mon, 3 September 2007, Petr \"Pasky\" Baudis wrote:\n> \n> > To hijack this post a bit, another patch in the queue (the incremental\n> > blame thingie) introduces blame.js. Do you think that we should keep the\n> > .js files separate, or instead have one big gitweb.js with everything?\n> > I'm inclined to the second possibility in order to reduce the number of\n> > requests, but it comes at a price of slightly worse maintainability.\n\nWhy is the maintainablility reduced?\n\ngitweb.perl is also a collection of different function, which are kept\nin one file. Where is the difference to a javascript file?\n\nKeeping everything into one file will make it more likely, that the\ncode is not developed totally different (in the terms of code style,\nvariable/function names, ...).\n\nIn the moment, there is the problem, which patch should introduce the\njs file. We need a common base patch, which introduces an empty\ngitweb.js.\n\nKeeping the two functions separate has problems. Every patch need to\nhook into the onload event. To avoid merge conflicts, my current patch\nsaves the old handler and overwrite it with its on version, which\ncalls back into the saved handler.\n\nIf we would have on js file, we can add in the base patch an empty\nJavaScript function for this.\n\nThen Hooking in the onload event would mean, to only add some new\nlines to the function. The resulting merge conflicts are\neasier to resolve (as they affect independet lines) compared to\nthe current '<body onload=\"hook1(); hook2();\">'\n\n> On the other hand if we have blame.js separate, we could load it\n> (require it) only for the 'blame' view, it means only when needed.\n> \n> gitweb.js would contain JavaScript code used by all (or almost all)\n> views, then...\n> \n> I don't think gitweb.js would be as large as gitweb.perl, if we are\n> talking about maintability ;-)\n\nThe size of gitweb.js should not matter. On a modern browser, the\nfirst request will fetch the whole Javascript file. For subseqent\nrequest, the webserver returns \"not modified\". Having two javascript\nfile means two checks.\n\nmfg Martin Kögler\n"}]}