threads / rfc / 43199

patchRe: [PATCH/RFC] gitweb: New improved patchset view

Subject: Re: [PATCH/RFC] gitweb: New improved patchset view

## tl;dr

8 messages between Oct 29, 2006 and Oct 30, 2006. Diffs are folded; open one to read it.

replies: 7people: 4as markdown or json

Jakub Narebski· Oct 29, 2006, 10:22 UTC · lore

[PATCH/RFC] gitweb: New improved patchset view

You should be able to check new commitdiff view at
  http://roke_DOT_dyndns_DOT_info/cgi-bin/gitweb/gitweb.cgi
(URL mangling courtesy vger banned words list, aaaarrghhh)
if I didn't screwed something again with firewall, and when my machine
is up; should be for at least an hour. Check for example:
  ?p=git.git;a=commitdiff;h=origin
  ?p=git.git;a=commitdiff;h=161332a521fe10c41979bcd493d95e2ac562b7f
  ?p=git.git;a=commitdiff;h=e12c095aa69d8aca0326eb11960427d9bf9e2db7
  ?p=git.git;a=commitdiff;h=82560983997c961d9deafe0074b787c8484c2e1d
and compare to (for example)
  http://repo.or.cz/w/git.git?a=commitdiff;h=82560983997c961d9deafe0074b787c8484c2e1d
or (even older gitweb)
  http://www.kernel.org/git/?p=git/git.git;a=commitdiff;h=887a612fef942dd3e7dae452e2dc582738b0fb41
BTW. this gitweb has also my previous "Slight improvement" patch applied.

Do you like it? What should be changed (code, output, style)? -- >8 -- Replace "gitweb diff header" with its full sha1 of blobs with "git diff" header and extended diff header. Change also highlighting of diffs.

Changes:
* "gitweb diff header" which looked for example like below:
    file:_<sha1 before>_ -> file:_<sha1 after>_
  where 'file' is file type and '<sha1>' is full sha1 of blob, is link
  and uses default link style is changed to
    diff --git a/<file before> b/<file after>
  where <file> is hidden link (i.e. underline on hover, only)
  to appropriate version of file. If file is added, a/<file> is not
  hyperlinked, if file is deleted, b/<file> is not hyperlinked.
* there is added "extended diff header", with <path> and <hash>
  hyperlinked (and <hash> shortened to 7 characters), and <mode>
  explained: '<mode>' is extnded to '<mode>/<symbolic mode> (<file type>)'.
* <file> hyperlinking should work also when <file> is originally
  quoted. For now we present filename quoted. This needed changes to
  parse_difftree_raw_line subroutine.
* from-file/to-file two-line header lines have slightly darker color
  than removed/added lines.
* chunk header has now delicate line above for easier finding chunk
  boundary, and top margin of 1px.
Controversial ideas:
* All links in patch header are hidden
* Hashes are shortened to 7 characters
* Filenames are presented quoted
* Marking of chunk beginning
* No hyperlink for renamed from/to header (bug)
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.css  |   46 ++++++++++++---
 gitweb/gitweb.perl |  159 ++++++++++++++++++++++++++++++---------------------
 2 files changed, 131 insertions(+), 74 deletions(-)
Show changes to 2 files +131 −74

gitweb/gitweb.css, gitweb/gitweb.perl

diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 83d900d..3aeceed 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -303,6 +303,33 @@ td.mode {
 	font-family: monospace;
 }
 
+
+div.diff.header,
+div.diff.extended_header {
+	white-space: normal;
+}
+
+div.diff.header {
+	font-weight: bold;
+
+	background-color: #edece6;
+
+	margin-top: 4px;
+	padding: 4px 0px 2px 0px;
+	border: solid #d9d8d1;
+	border-width: 1px 0px 1px 0px;
+}
+
+div.diff.extended_header,
+div.diff.extended_header a.list {
+	color: #777777;
+}
+
+div.diff.extended_header {
+	background-color: #f6f5ee;
+	padding: 2px 0px 2px 0px;
+}
+
 div.diff a.list {
 	text-decoration: none;
 }
@@ -312,31 +339,34 @@ div.diff a.list:hover {
 }
 
 div.diff.to_file a.list,
-div.diff.to_file,
+div.diff.to_file {
+	color: #007000;
+}
+
 div.diff.add {
 	color: #008800;
 }
 
 div.diff.from_file a.list,
-div.diff.from_file,
+div.diff.from_file {
+	color: #aa0000;
+}
+
 div.diff.rem {
 	color: #cc0000;
 }
 
 div.diff.chunk_header {
 	color: #990099;
+	border: dotted #ffbbff;
+	border-width: 1px 0px 0px 0px;
+	margin-top: 1px;
 }
 
 div.diff.incomplete {
 	color: #cccccc;
 }
 
-div.diff_info {
-	font-family: monospace;
-	color: #000099;
-	background-color: #edece6;
-	font-style: italic;
-}
 
 div.index_include {
 	border: solid #d9d8d1;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index cbab3c9..2d971ac 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1255,9 +1255,12 @@ sub parse_difftree_raw_line {
 		$res{'status'} = $5;
 		$res{'similarity'} = $6;
 		if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
-			($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7);
+			($res{'from_file_raw'}, $res{'to_file_raw'}) = split("\t", $7);
+			$res{'from_file'} = unquote($res{'from_file_raw'});
+			$res{'to_file'}   = unquote($res{'to_file_raw'});
 		} else {
-			$res{'file'} = unquote($7);
+			$res{'file_raw'} = $7;
+			$res{'file'} = unquote($res{'file_raw'});
 		}
 	}
 	# 'c512b523472485aef4fff9e57b229d9d243c967f'
@@ -2024,6 +2027,7 @@ sub git_patchset_body {
 	my $in_header = 0;
 	my $patch_found = 0;
 	my $diffinfo;
+	my (@from_subst, @to_subst);
 
 	print "<div class=\"patchset\">\n";
 
@@ -2033,6 +2037,7 @@ sub git_patchset_body {
 
 		if ($patch_line =~ m/^diff /) { # "git diff" header
 			# beginning of patch (in patchset)
+
 			if ($patch_found) {
 				# close previous patch
 				print "</div>\n"; # class="patch"
@@ -2042,11 +2047,59 @@ sub git_patchset_body {
 			}
 			print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
 
+			# read and prepare patch information
 			if (ref($difftree->[$patch_idx]) eq "HASH") {
+				# pre-parsed (or generated by hand)
 				$diffinfo = $difftree->[$patch_idx];
 			} else {
 				$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
 			}
+			if ($diffinfo->{'status'} ne "A") { # not new (added) file
+				my $quot = '';
+				my $from_text;
+				my $file_raw = $diffinfo->{'from_file_raw'} || $diffinfo->{'file_raw'};
+				if ($file_raw =~ s/^"(.*)"$/\1/) {
+					$from_text = qq("a/$file_raw");
+					$quot = '"';
+				} else {
+					$from_text =  qq(a/$file_raw);
+				}
+				my $file = $diffinfo->{'from_file'} || $diffinfo->{'file'};
+				my $from_link =
+					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
+					                      hash=>$diffinfo->{'from_id'}, file_name=>$file),
+					        -class => "list"}, esc_html($file_raw));
+				my $hash_link =
+					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
+					                      hash=>$diffinfo->{'to_id'}, file_name=>$file),
+					        -class => "list"}, substr($diffinfo->{'from_id'},0,7));
+				@from_subst = 
+					($from_text, "${quot}a/$from_link${quot}",
+					$diffinfo->{'from_id'} . '\.\.', "$hash_link..");
+			}
+			if ($diffinfo->{'status'} ne "D") { # not deleted file
+				my $quot = '';
+				my $to_text;
+				my $file_raw = $diffinfo->{'to_file_raw'} || $diffinfo->{'file_raw'};
+				if ($file_raw =~ s/^"(.*)"$/\1/) {
+					$to_text = qq("b/$file_raw");
+					$quot = '"';
+				} else {
+					$to_text =  qq(b/$file_raw);
+				}
+				my $file = $diffinfo->{'to_file'} || $diffinfo->{'file'};
+				my $to_link =
+					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
+					                      hash=>$diffinfo->{'to_id'}, file_name=>$file),
+					        -class => "list"}, esc_html($file_raw));
+				my $hash_link =
+					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
+					                      hash=>$diffinfo->{'to_id'}, file_name=>$file),
+					        -class => "list"}, substr($diffinfo->{'to_id'},0,7));
+				@to_subst =
+					($to_text, "${quot}b/$to_link${quot}",
+					 '\.\.' . $diffinfo->{'to_id'}, "..$hash_link");
+			}
 			$patch_idx++;
 
 			# for now we skip empty patches
@@ -2056,82 +2109,56 @@ sub git_patchset_body {
 				next LINE;
 			}
 
-			if ($diffinfo->{'status'} eq "A") { # added
-				print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'to_id'}) . " (new)" .
-				      "</div>\n"; # class="diff_info"
-
-			} elsif ($diffinfo->{'status'} eq "D") { # deleted
-				print "<div class=\"diff_info\">" . file_type($diffinfo->{'from_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-				                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'from_id'}) . " (deleted)" .
-				      "</div>\n"; # class="diff_info"
-
-			} elsif ($diffinfo->{'status'} eq "R" || # renamed
-			         $diffinfo->{'status'} eq "C" || # copied
-			         $diffinfo->{'status'} eq "2") { # with two filenames (from git_blobdiff)
-				print "<div class=\"diff_info\">" .
-				      file_type($diffinfo->{'from_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-				                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'from_file'})},
-				              $diffinfo->{'from_id'}) .
-				      " -> " .
-				      file_type($diffinfo->{'to_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'to_file'})},
-				              $diffinfo->{'to_id'});
-				print "</div>\n"; # class="diff_info"
-
-			} else { # modified, mode changed, ...
-				print "<div class=\"diff_info\">" .
-				      file_type($diffinfo->{'from_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-				                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'from_id'}) .
-				      " -> " .
-				      file_type($diffinfo->{'to_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'to_id'});
-				print "</div>\n"; # class="diff_info"
-			}
+			# print "git diff" header
+			$patch_line =~ s/$from_subst[0]/$from_subst[1]/ if @from_subst;
+			$patch_line =~ s/$to_subst[0]/$to_subst[1]/ if @to_subst;
+			print "<div class=\"diff header\">$patch_line</div>\n";
 
-			#print "<div class=\"diff extended_header\">\n";
+			print "<div class=\"diff extended_header\">\n";
 			$in_header = 1;
 			next LINE;
 		} # start of patch in patchset
 
+		if ($in_header) {
+			if ($patch_line !~ m/^---/) {
+				# match <path>
+				if ($patch_line =~ m|a/|) {
+					$patch_line =~ s/$from_subst[0]/$from_subst[1]/ if @from_subst;
+				}
+				if ($patch_line =~ m|b/|) {
+					$patch_line =~ s/$to_subst[0]/$to_subst[1]/ if @to_subst;
+				}
+				# match <mode>
+				if ($patch_line =~ m/\s(\d{6})$/) {
+					$patch_line .= '/' . mode_str($1) . ' (' . file_type($1) . ')';
+				}
+				# match <hash>
+				if ($patch_line =~ m/^index/) {
+					$patch_line =~ s/0{40}/'0' x 7/e;
+					$patch_line =~ s/$from_subst[2]/$from_subst[3]/ if @from_subst;
+					$patch_line =~ s/$to_subst[2]/$to_subst[3]/ if @to_subst;
+				}
+				print $patch_line . "<br/>\n";
 
-		if ($in_header && $patch_line =~ m/^---/) {
-			#print "</div>\n"; # class="diff extended_header"
-			$in_header = 0;
+			} else {
+				#$patch_line =~ m/^---/;
+				print "</div>\n"; # class="diff extended_header"
+				$in_header = 0;
+
+				$patch_line =~ s/$from_subst[0]/$from_subst[1]/ if @from_subst;
+				print "<div class=\"diff from_file\">$patch_line</div>\n";
 
-			my $file = $diffinfo->{'from_file'};
-			$file  ||= $diffinfo->{'file'};
-			$file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-			                               hash=>$diffinfo->{'from_id'}, file_name=>$file),
-			                -class => "list"}, esc_html($file));
-			$patch_line =~ s|a/.*$|a/$file|g;
-			print "<div class=\"diff from_file\">$patch_line</div>\n";
+				$patch_line = <$fd>;
+				chomp $patch_line;
 
-			$patch_line = <$fd>;
-			chomp $patch_line;
+				#$patch_line =~ m/^+++/;
+				$patch_line =~ s/$to_subst[0]/$to_subst[1]/ if @to_subst;
+				print "<div class=\"diff to_file\">$patch_line</div>\n";
 
-			#$patch_line =~ m/^+++/;
-			$file    = $diffinfo->{'to_file'};
-			$file  ||= $diffinfo->{'file'};
-			$file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-			                               hash=>$diffinfo->{'to_id'}, file_name=>$file),
-			                -class => "list"}, esc_html($file));
-			$patch_line =~ s|b/.*|b/$file|g;
-			print "<div class=\"diff to_file\">$patch_line</div>\n";
+			}
 
 			next LINE;
 		}
-		next LINE if $in_header;
 
 		print format_diff_line($patch_line);
 	}
-- 
1.4.3.3



-------------------------------------------------------

-- 
Jakub Narebski
Anand Kumria· Oct 29, 2006, 12:44 UTC · re: Jakub Narebski · lore
On Sun, 29 Oct 2006 11:22:30 +0100, Jakub Narebski wrote:
Show 16 quoted lines
> You should be able to check new commitdiff view at
>   http://roke_DOT_dyndns_DOT_info/cgi-bin/gitweb/gitweb.cgi
> (URL mangling courtesy vger banned words list, aaaarrghhh)
> if I didn't screwed something again with firewall, and when my machine
> is up; should be for at least an hour. Check for example:
>   ?p=git.git;a=commitdiff;h=origin
>   ?p=git.git;a=commitdiff;h=161332a521fe10c41979bcd493d95e2ac562b7f
>   ?p=git.git;a=commitdiff;h=e12c095aa69d8aca0326eb11960427d9bf9e2db7
>   ?p=git.git;a=commitdiff;h=82560983997c961d9deafe0074b787c8484c2e1d
> and compare to (for example)
>   http://repo.or.cz/w/git.git?a=commitdiff;h=82560983997c961d9deafe0074b787c8484c2e1d
> or (even older gitweb)
>   http://www.kernel.org/git/?p=git/git.git;a=commitdiff;h=887a612fef942dd3e7dae452e2dc582738b0fb41
> BTW. this gitweb has also my previous "Slight improvement" patch applied.
> 
> Do you like it? What should be changed (code, output, style)?

I think your version looks a lot nicer but I believe that the commit message area should be in a fixed-point font. In general it won't be a problem but if anyone should choose to insert a diagram or something else that assume a fixed-width display - it won't look good.

Anand
Luben Tuikov· Oct 29, 2006, 19:38 UTC · re: Anand Kumria · lore
--- Anand Kumria <wildfire@progsoc.org> wrote:
> I think your version looks a lot nicer but I believe that the commit
> message area should be in a fixed-point font. In general it won't be a
> problem but if anyone should choose to insert a diagram or something else
> that assume a fixed-width display - it won't look good.
Thanks for catching this!

Jakub, I believe I submitted a patch to change that to fixed point and you can see the reasons in the commit message. See commit 4b7ce6e2d6ba088da50de1df38b040ea2c0b8f18.

Please change it to fixed point.
    Luben
Luben Tuikov· Oct 29, 2006, 19:31 UTC · re: Jakub Narebski · lore
--- Jakub Narebski <jnareb@gmail.com> wrote:
Show 9 quoted lines
> Changes:
> * "gitweb diff header" which looked for example like below:
>     file:_<sha1 before>_ -> file:_<sha1 after>_
>   where 'file' is file type and '<sha1>' is full sha1 of blob, is link
>   and uses default link style is changed to
>     diff --git a/<file before> b/<file after>
>   where <file> is hidden link (i.e. underline on hover, only)
>   to appropriate version of file. If file is added, a/<file> is not
>   hyperlinked, if file is deleted, b/<file> is not hyperlinked.
I like it and I like the "hidden" links.
> * there is added "extended diff header", with <path> and <hash>
>   hyperlinked (and <hash> shortened to 7 characters), and <mode>
>   explained: '<mode>' is extnded to '<mode>/<symbolic mode> (<file type>)'.
I like that too, but would leave "100644/-rw-r--r-- (file)" out.

There is a bug in the code: the first index link is the same as the second, while the first should upload the sha-7 it points to. For example: index 743f02b..c821e22 Both point to c821e22. Please fix that.

> * <file> hyperlinking should work also when <file> is originally
>   quoted. For now we present filename quoted. This needed changes to
>   parse_difftree_raw_line subroutine.

I didn't see where you've quoted file names, but I'm a bit hesitant to quote anything unnecessarily in the visual output.

> * from-file/to-file two-line header lines have slightly darker color
>   than removed/added lines.
Good.
> * chunk header has now delicate line above for easier finding chunk
>   boundary, and top margin of 1px.
Good.
> Controversial ideas:
> * All links in patch header are hidden
Love those hidden gems.
> * Hashes are shortened to 7 characters

That's ok as long as the output is consisent with real git diff. That is, a user using git can recognize this commitdiff output and a user using this gitweb commitdiff output can recognize a git diff output.

> * Filenames are presented quoted
I wouldn't do that.
> * Marking of chunk beginning
I like the fine lines and their color as it is shown in your server.
> * No hyperlink for renamed from/to header (bug)
I'm sure you'll fix that.

Overall I like this patch. Why? Because it makes gitweb commitdiff output as similar as possible to git-diff output. This is always a good thing, since both beginners and advanced git users can recognize one or the other depending where they are coming from (gitweb or git).

   Luben
Show 323 quoted lines
> 
> Signed-off-by: Jakub Narebski <jnareb@gmail.com>
> ---
>  gitweb/gitweb.css  |   46 ++++++++++++---
>  gitweb/gitweb.perl |  159 ++++++++++++++++++++++++++++++---------------------
>  2 files changed, 131 insertions(+), 74 deletions(-)
> 
> diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
> index 83d900d..3aeceed 100644
> --- a/gitweb/gitweb.css
> +++ b/gitweb/gitweb.css
> @@ -303,6 +303,33 @@ td.mode {
>  	font-family: monospace;
>  }
>  
> +
> +div.diff.header,
> +div.diff.extended_header {
> +	white-space: normal;
> +}
> +
> +div.diff.header {
> +	font-weight: bold;
> +
> +	background-color: #edece6;
> +
> +	margin-top: 4px;
> +	padding: 4px 0px 2px 0px;
> +	border: solid #d9d8d1;
> +	border-width: 1px 0px 1px 0px;
> +}
> +
> +div.diff.extended_header,
> +div.diff.extended_header a.list {
> +	color: #777777;
> +}
> +
> +div.diff.extended_header {
> +	background-color: #f6f5ee;
> +	padding: 2px 0px 2px 0px;
> +}
> +
>  div.diff a.list {
>  	text-decoration: none;
>  }
> @@ -312,31 +339,34 @@ div.diff a.list:hover {
>  }
>  
>  div.diff.to_file a.list,
> -div.diff.to_file,
> +div.diff.to_file {
> +	color: #007000;
> +}
> +
>  div.diff.add {
>  	color: #008800;
>  }
>  
>  div.diff.from_file a.list,
> -div.diff.from_file,
> +div.diff.from_file {
> +	color: #aa0000;
> +}
> +
>  div.diff.rem {
>  	color: #cc0000;
>  }
>  
>  div.diff.chunk_header {
>  	color: #990099;
> +	border: dotted #ffbbff;
> +	border-width: 1px 0px 0px 0px;
> +	margin-top: 1px;
>  }
>  
>  div.diff.incomplete {
>  	color: #cccccc;
>  }
>  
> -div.diff_info {
> -	font-family: monospace;
> -	color: #000099;
> -	background-color: #edece6;
> -	font-style: italic;
> -}
>  
>  div.index_include {
>  	border: solid #d9d8d1;
> diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
> index cbab3c9..2d971ac 100755
> --- a/gitweb/gitweb.perl
> +++ b/gitweb/gitweb.perl
> @@ -1255,9 +1255,12 @@ sub parse_difftree_raw_line {
>  		$res{'status'} = $5;
>  		$res{'similarity'} = $6;
>  		if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
> -			($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7);
> +			($res{'from_file_raw'}, $res{'to_file_raw'}) = split("\t", $7);
> +			$res{'from_file'} = unquote($res{'from_file_raw'});
> +			$res{'to_file'}   = unquote($res{'to_file_raw'});
>  		} else {
> -			$res{'file'} = unquote($7);
> +			$res{'file_raw'} = $7;
> +			$res{'file'} = unquote($res{'file_raw'});
>  		}
>  	}
>  	# 'c512b523472485aef4fff9e57b229d9d243c967f'
> @@ -2024,6 +2027,7 @@ sub git_patchset_body {
>  	my $in_header = 0;
>  	my $patch_found = 0;
>  	my $diffinfo;
> +	my (@from_subst, @to_subst);
>  
>  	print "<div class=\"patchset\">\n";
>  
> @@ -2033,6 +2037,7 @@ sub git_patchset_body {
>  
>  		if ($patch_line =~ m/^diff /) { # "git diff" header
>  			# beginning of patch (in patchset)
> +
>  			if ($patch_found) {
>  				# close previous patch
>  				print "</div>\n"; # class="patch"
> @@ -2042,11 +2047,59 @@ sub git_patchset_body {
>  			}
>  			print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
>  
> +			# read and prepare patch information
>  			if (ref($difftree->[$patch_idx]) eq "HASH") {
> +				# pre-parsed (or generated by hand)
>  				$diffinfo = $difftree->[$patch_idx];
>  			} else {
>  				$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
>  			}
> +			if ($diffinfo->{'status'} ne "A") { # not new (added) file
> +				my $quot = '';
> +				my $from_text;
> +				my $file_raw = $diffinfo->{'from_file_raw'} || $diffinfo->{'file_raw'};
> +				if ($file_raw =~ s/^"(.*)"$/\1/) {
> +					$from_text = qq("a/$file_raw");
> +					$quot = '"';
> +				} else {
> +					$from_text =  qq(a/$file_raw);
> +				}
> +				my $file = $diffinfo->{'from_file'} || $diffinfo->{'file'};
> +				my $from_link =
> +					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
> +					                      hash=>$diffinfo->{'from_id'}, file_name=>$file),
> +					        -class => "list"}, esc_html($file_raw));
> +				my $hash_link =
> +					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
> +					                      hash=>$diffinfo->{'to_id'}, file_name=>$file),
> +					        -class => "list"}, substr($diffinfo->{'from_id'},0,7));
> +				@from_subst = 
> +					($from_text, "${quot}a/$from_link${quot}",
> +					$diffinfo->{'from_id'} . '\.\.', "$hash_link..");
> +			}
> +			if ($diffinfo->{'status'} ne "D") { # not deleted file
> +				my $quot = '';
> +				my $to_text;
> +				my $file_raw = $diffinfo->{'to_file_raw'} || $diffinfo->{'file_raw'};
> +				if ($file_raw =~ s/^"(.*)"$/\1/) {
> +					$to_text = qq("b/$file_raw");
> +					$quot = '"';
> +				} else {
> +					$to_text =  qq(b/$file_raw);
> +				}
> +				my $file = $diffinfo->{'to_file'} || $diffinfo->{'file'};
> +				my $to_link =
> +					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
> +					                      hash=>$diffinfo->{'to_id'}, file_name=>$file),
> +					        -class => "list"}, esc_html($file_raw));
> +				my $hash_link =
> +					$cgi->a({-href => href(action=>"blob", hash_base=>$hash_base,
> +					                      hash=>$diffinfo->{'to_id'}, file_name=>$file),
> +					        -class => "list"}, substr($diffinfo->{'to_id'},0,7));
> +				@to_subst =
> +					($to_text, "${quot}b/$to_link${quot}",
> +					 '\.\.' . $diffinfo->{'to_id'}, "..$hash_link");
> +			}
>  			$patch_idx++;
>  
>  			# for now we skip empty patches
> @@ -2056,82 +2109,56 @@ sub git_patchset_body {
>  				next LINE;
>  			}
>  
> -			if ($diffinfo->{'status'} eq "A") { # added
> -				print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
> -				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
> -				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
> -				              $diffinfo->{'to_id'}) . " (new)" .
> -				      "</div>\n"; # class="diff_info"
> -
> -			} elsif ($diffinfo->{'status'} eq "D") { # deleted
> -				print "<div class=\"diff_info\">" . file_type($diffinfo->{'from_mode'}) . ":" .
> -				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
> -				                             hash=>$diffinfo->{'from_id'},
> file_name=>$diffinfo->{'file'})},
> -				              $diffinfo->{'from_id'}) . " (deleted)" .
> -				      "</div>\n"; # class="diff_info"
> -
> -			} elsif ($diffinfo->{'status'} eq "R" || # renamed
> -			         $diffinfo->{'status'} eq "C" || # copied
> -			         $diffinfo->{'status'} eq "2") { # with two filenames (from git_blobdiff)
> -				print "<div class=\"diff_info\">" .
> -				      file_type($diffinfo->{'from_mode'}) . ":" .
> -				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
> -				                             hash=>$diffinfo->{'from_id'},
> file_name=>$diffinfo->{'from_file'})},
> -				              $diffinfo->{'from_id'}) .
> -				      " -> " .
> -				      file_type($diffinfo->{'to_mode'}) . ":" .
> -				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
> -				                             hash=>$diffinfo->{'to_id'},
> file_name=>$diffinfo->{'to_file'})},
> -				              $diffinfo->{'to_id'});
> -				print "</div>\n"; # class="diff_info"
> -
> -			} else { # modified, mode changed, ...
> -				print "<div class=\"diff_info\">" .
> -				      file_type($diffinfo->{'from_mode'}) . ":" .
> -				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
> -				                             hash=>$diffinfo->{'from_id'},
> file_name=>$diffinfo->{'file'})},
> -				              $diffinfo->{'from_id'}) .
> -				      " -> " .
> -				      file_type($diffinfo->{'to_mode'}) . ":" .
> -				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
> -				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
> -				              $diffinfo->{'to_id'});
> -				print "</div>\n"; # class="diff_info"
> -			}
> +			# print "git diff" header
> +			$patch_line =~ s/$from_subst[0]/$from_subst[1]/ if @from_subst;
> +			$patch_line =~ s/$to_subst[0]/$to_subst[1]/ if @to_subst;
> +			print "<div class=\"diff header\">$patch_line</div>\n";
>  
> -			#print "<div class=\"diff extended_header\">\n";
> +			print "<div class=\"diff extended_header\">\n";
>  			$in_header = 1;
>  			next LINE;
>  		} # start of patch in patchset
>  
> +		if ($in_header) {
> +			if ($patch_line !~ m/^---/) {
> +				# match <path>
> +				if ($patch_line =~ m|a/|) {
> +					$patch_line =~ s/$from_subst[0]/$from_subst[1]/ if @from_subst;
> +				}
> +				if ($patch_line =~ m|b/|) {
> +					$patch_line =~ s/$to_subst[0]/$to_subst[1]/ if @to_subst;
> +				}
> +				# match <mode>
> +				if ($patch_line =~ m/\s(\d{6})$/) {
> +					$patch_line .= '/' . mode_str($1) . ' (' . file_type($1) . ')';
> +				}
> +				# match <hash>
> +				if ($patch_line =~ m/^index/) {
> +					$patch_line =~ s/0{40}/'0' x 7/e;
> +					$patch_line =~ s/$from_subst[2]/$from_subst[3]/ if @from_subst;
> +					$patch_line =~ s/$to_subst[2]/$to_subst[3]/ if @to_subst;
> +				}
> +				print $patch_line . "<br/>\n";
>  
> -		if ($in_header && $patch_line =~ m/^---/) {
> -			#print "</div>\n"; # class="diff extended_header"
> -			$in_header = 0;
> +			} else {
> +				#$patch_line =~ m/^---/;
> +				print "</div>\n"; # class="diff extended_header"
> +				$in_header = 0;
> +
> +				$patch_line =~ s/$from_subst[0]/$from_subst[1]/ if @from_subst;
> +				print "<div class=\"diff from_file\">$patch_line</div>\n";
>  
> -			my $file = $diffinfo->{'from_file'};
> -			$file  ||= $diffinfo->{'file'};
> -			$file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
> -			                               hash=>$diffinfo->{'from_id'}, file_name=>$file),
> -			                -class => "list"}, esc_html($file));
> -			$patch_line =~ s|a/.*$|a/$file|g;
> -			print "<div class=\"diff from_file\">$patch_line</div>\n";
> +				$patch_line = <$fd>;
> +				chomp $patch_line;
>  
> -			$patch_line = <$fd>;
> -			chomp $patch_line;
> +				#$patch_line =~ m/^+++/;
> +				$patch_line =~ s/$to_subst[0]/$to_subst[1]/ if @to_subst;
> +				print "<div class=\"diff to_file\">$patch_line</div>\n";
>  
> -			#$patch_line =~ m/^+++/;
> -			$file    = $diffinfo->{'to_file'};
> -			$file  ||= $diffinfo->{'file'};
> -			$file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
> -			                               hash=>$diffinfo->{'to_id'}, file_name=>$file),
> -			                -class => "list"}, esc_html($file));
> -			$patch_line =~ s|b/.*|b/$file|g;
> -			print "<div class=\"diff to_file\">$patch_line</div>\n";
> +			}
>  
>  			next LINE;
>  		}
> -		next LINE if $in_header;
>  
>  		print format_diff_line($patch_line);
>  	}
> -- 
> 1.4.3.3
> 
> 
> 
> -------------------------------------------------------
> 
> -- 
> Jakub Narebski
> Poland
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
Jakub Narebski· Oct 29, 2006, 23:51 UTC · re: Jakub Narebski · lore

[PATCH/RFC (take 2)] gitweb: New improved patchset view

Replace "gitweb diff header" with its full sha1 of blobs and replace it by "git diff" header and extended diff header. Change also somewhat highlighting of diffs.

Changes:
* "gitweb diff header" which looked for example like below:
    file:_<sha1 before>_ -> file:_<sha1 after>_
  where 'file' is file type and '<sha1>' is full sha1 of blob is
  changed to
    diff --git _a/<file before>_ _b/<file after>_
  In both cases links are visible and use default link style. If file
  is added, a/<file> is not hyperlinked, if file is deleted, b/<file>
  is not hyperlinked.
* there is added "extended diff header", with <path> and <hash>
  hyperlinked (and <hash> shortened to 7 characters), and <mode>
  explained: '<mode>' is extended to '<mode> (<file type>)'.
* <file> hyperlinking should work also when <file> is originally
  quoted. For now we present filename quoted. This needed changes to
  parse_difftree_raw_line subroutine. And doesn't work: perhaps
  unquote is broken.
* from-file/to-file two-line header lines have slightly darker color
  than removed/added lines.
* chunk header has now delicate line above for easier finding chunk
  boundary, and top margin of 1px.

WORK IN PROGRESS: might not work (and actually doesn't work correctly) for strange filenames, i.e. filenames contaning either metacharacters or having TAB, LF, backslash or doublequote in them.

Code should be much more clean, by the way.
Signed-off-by: Jakub Narebski <jnareb@gmail.com>
---
 gitweb/gitweb.css  |   46 +++++++++++---
 gitweb/gitweb.perl |  178 +++++++++++++++++++++++++++++++++-------------------
 2 files changed, 151 insertions(+), 73 deletions(-)
Show changes to 2 files +151 −73

gitweb/gitweb.css, gitweb/gitweb.perl

diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css
index 83d900d..3aeceed 100644
--- a/gitweb/gitweb.css
+++ b/gitweb/gitweb.css
@@ -303,6 +303,33 @@ td.mode {
 	font-family: monospace;
 }
 
+
+div.diff.header,
+div.diff.extended_header {
+	white-space: normal;
+}
+
+div.diff.header {
+	font-weight: bold;
+
+	background-color: #edece6;
+
+	margin-top: 4px;
+	padding: 4px 0px 2px 0px;
+	border: solid #d9d8d1;
+	border-width: 1px 0px 1px 0px;
+}
+
+div.diff.extended_header,
+div.diff.extended_header a.list {
+	color: #777777;
+}
+
+div.diff.extended_header {
+	background-color: #f6f5ee;
+	padding: 2px 0px 2px 0px;
+}
+
 div.diff a.list {
 	text-decoration: none;
 }
@@ -312,31 +339,34 @@ div.diff a.list:hover {
 }
 
 div.diff.to_file a.list,
-div.diff.to_file,
+div.diff.to_file {
+	color: #007000;
+}
+
 div.diff.add {
 	color: #008800;
 }
 
 div.diff.from_file a.list,
-div.diff.from_file,
+div.diff.from_file {
+	color: #aa0000;
+}
+
 div.diff.rem {
 	color: #cc0000;
 }
 
 div.diff.chunk_header {
 	color: #990099;
+	border: dotted #ffbbff;
+	border-width: 1px 0px 0px 0px;
+	margin-top: 1px;
 }
 
 div.diff.incomplete {
 	color: #cccccc;
 }
 
-div.diff_info {
-	font-family: monospace;
-	color: #000099;
-	background-color: #edece6;
-	font-style: italic;
-}
 
 div.index_include {
 	border: solid #d9d8d1;
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index cbab3c9..a5a140c 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1255,9 +1255,12 @@ sub parse_difftree_raw_line {
 		$res{'status'} = $5;
 		$res{'similarity'} = $6;
 		if ($res{'status'} eq 'R' || $res{'status'} eq 'C') { # renamed or copied
-			($res{'from_file'}, $res{'to_file'}) = map { unquote($_) } split("\t", $7);
+			($res{'from_file_raw'}, $res{'to_file_raw'}) = split("\t", $7);
+			$res{'from_file'} = unquote($res{'from_file_raw'});
+			$res{'to_file'}   = unquote($res{'to_file_raw'});
 		} else {
-			$res{'file'} = unquote($7);
+			$res{'file_raw'} = $7;
+			$res{'file'} = unquote($res{'file_raw'});
 		}
 	}
 	# 'c512b523472485aef4fff9e57b229d9d243c967f'
@@ -2023,7 +2026,9 @@ sub git_patchset_body {
 	my $patch_idx = 0;
 	my $in_header = 0;
 	my $patch_found = 0;
+	my $skip_patch = 0;
 	my $diffinfo;
+	my (%from, %to);
 
 	print "<div class=\"patchset\">\n";
 
@@ -2033,6 +2038,8 @@ sub git_patchset_body {
 
 		if ($patch_line =~ m/^diff /) { # "git diff" header
 			# beginning of patch (in patchset)
+			$skip_patch = 0;
+
 			if ($patch_found) {
 				# close previous patch
 				print "</div>\n"; # class="patch"
@@ -2042,96 +2049,137 @@ sub git_patchset_body {
 			}
 			print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n";
 
+			# read and prepare patch information
 			if (ref($difftree->[$patch_idx]) eq "HASH") {
+				# pre-parsed (or generated by hand)
 				$diffinfo = $difftree->[$patch_idx];
 			} else {
 				$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
 			}
+			if ($diffinfo->{'status'} ne "A") { # not new (added) file
+				$from{'name'} = $diffinfo->{'from_file_raw'} || $diffinfo->{'file_raw'};
+				 # because of "a/file" not a/"file"
+				$from{'quoted'} = ($from{'name'} =~ s/^"(.*)"$/$1/);
+
+				my $file = $diffinfo->{'from_file'} || $diffinfo->{'file'};
+				$from{'href'} = href(action=>"blob", hash_base=>$hash_parent,
+				                     hash=>$diffinfo->{'from_id'}, file_name=>$file);
+			}
+			if ($diffinfo->{'status'} ne "D") { # not deleted file
+				$to{'name'} = $diffinfo->{'to_file_raw'} || $diffinfo->{'file_raw'};
+				# because of "b/file" not b/"file"
+				$to{'quoted'} = ($to{'name'} =~ s/^"(.*)"$/$1/);
+
+				my $file = $diffinfo->{'to_file'} || $diffinfo->{'file'};
+				$to{'href'} = href(action=>"blob", hash_base=>$hash,
+				                   hash=>$diffinfo->{'to_id'}, file_name=>$file);
+			}
 			$patch_idx++;
 
 			# for now we skip empty patches
 			if ($diffinfo->{'from_id'} eq $diffinfo->{'to_id'}) {
 				# no change, empty patch
 				$in_header = 1;
+				$skip_patch = 0;
 				next LINE;
 			}
 
-			if ($diffinfo->{'status'} eq "A") { # added
-				print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'to_id'}) . " (new)" .
-				      "</div>\n"; # class="diff_info"
-
-			} elsif ($diffinfo->{'status'} eq "D") { # deleted
-				print "<div class=\"diff_info\">" . file_type($diffinfo->{'from_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-				                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'from_id'}) . " (deleted)" .
-				      "</div>\n"; # class="diff_info"
-
-			} elsif ($diffinfo->{'status'} eq "R" || # renamed
-			         $diffinfo->{'status'} eq "C" || # copied
-			         $diffinfo->{'status'} eq "2") { # with two filenames (from git_blobdiff)
-				print "<div class=\"diff_info\">" .
-				      file_type($diffinfo->{'from_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-				                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'from_file'})},
-				              $diffinfo->{'from_id'}) .
-				      " -> " .
-				      file_type($diffinfo->{'to_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'to_file'})},
-				              $diffinfo->{'to_id'});
-				print "</div>\n"; # class="diff_info"
-
-			} else { # modified, mode changed, ...
-				print "<div class=\"diff_info\">" .
-				      file_type($diffinfo->{'from_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-				                             hash=>$diffinfo->{'from_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'from_id'}) .
-				      " -> " .
-				      file_type($diffinfo->{'to_mode'}) . ":" .
-				      $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-				                             hash=>$diffinfo->{'to_id'}, file_name=>$diffinfo->{'file'})},
-				              $diffinfo->{'to_id'});
-				print "</div>\n"; # class="diff_info"
+			# print "git diff" header
+			if ($from{'name'}) {
+				my $from_link = $cgi->a({-href => $from{'href'}, -class => "path"},
+				                        'a/' . esc_html($from{'name'}));
+				my ($q, $qq) = $from{'quoted'} ? ('"', '&quot;') : ('', '');
+				$patch_line =~ s|${q}a/\Q$from{'name'}\E${q}|${qq}$from_link${qq}|;
+			} else {
+				# at least one of %from and %to must be set
+				$patch_line =~ s|(["]?a/\Q$to{'name'}\E["]?)|esc_html($1)|e;
+			}
+			if ($to{'name'}) {
+				my $to_link = $cgi->a({-href => $to{'href'}, -class => "path"},
+				                      'b/' . esc_html($to{'name'}));
+				my ($q, $qq) = $to{'quoted'} ? ('"', '&quot;') : ('', '');
+				$patch_line =~ s|${q}b/\Q$to{'name'}\E${q}$|${qq}$to_link${qq}|;
+			} else {
+				# at least one of %from and %to must be set
+				$patch_line =~ s|(["]?b/\Q$from{'name'}\E["]?)$|esc_html($1)|e;
 			}
 
-			#print "<div class=\"diff extended_header\">\n";
+			print "<div class=\"diff header\">$patch_line</div>\n";
+			print "<div class=\"diff extended_header\">\n";
 			$in_header = 1;
 			next LINE;
+		} else {
+			next LINE if $skip_patch;
 		} # start of patch in patchset
 
+		if ($in_header) {
+			if ($patch_line !~ m/^---/) {
+				# match <path>
+				if ($patch_line =~ m!^(copy|rename) from ! && $from{'name'}) {
+					my $qq = $from{'quoted'} ? '&quot;' : '';
+					my $from_link = $cgi->a({-href=>$from{'href'},-class=>"list"},
+					                        esc_html($from{'name'}));
+					$patch_line =~ s!from .*$!from $qq$from_link$qq!;
+				}
+				if ($patch_line =~ m!^(copy|rename) to ! && $to{'name'}) {
+					my $qq = $to{'quoted'} ? '&quot;' : '';
+					my $to_link = $cgi->a({-href=>$to{'href'},-class=>"list"},
+					                      esc_html($to{'name'}));
+					$patch_line =~ s!to .*$!to $qq$to_link$qq!;
+				}
+				# match <mode>
+				if ($patch_line =~ m/\s(\d{6})$/) {
+					$patch_line .= '<span class="info"> (' . file_type($1) . ')</span>';
+				}
+				# match <hash>
+				if ($patch_line =~ m/^index/) {
+					my ($from_link, $to_link);
+					if ($from{'href'}) {
+						$from_link = $cgi->a({-href=>$from{'href'},-class=>"list"},
+						                     substr($diffinfo->{'from_id'},0,7));
+					} else {
+						$from_link = '0' x 7;
+					}
+					if ($to{'href'}) {
+						$to_link = $cgi->a({-href=>$to{'href'},-class=>"list"},
+						                   substr($diffinfo->{'to_id'},0,7));
+					} else {
+						$to_link = '0' x 7;
+					}
+					my ($from_id, $to_id) = ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
+					$patch_line =~ s!$from_id\.\.$to_id!$from_link..$to_link!;
+				}
+				print $patch_line . "<br/>\n";
 
-		if ($in_header && $patch_line =~ m/^---/) {
-			#print "</div>\n"; # class="diff extended_header"
-			$in_header = 0;
+			} else {
+				#$patch_line =~ m/^---/;
+				print "</div>\n"; # class="diff extended_header"
+				$in_header = 0;
+
+				if ($from{'name'}) {
+					my $qq = $from{'quoted'} ? '&quot;' : '';
+					my $from_link = $cgi->a({-href=>$from{'href'},-class=>"list"},
+					                        esc_html($from{'name'}));
+					$patch_line =~ s!["]?a/.*$!${qq}a/$from_link${qq}!;
+				}
+				print "<div class=\"diff from_file\">$patch_line</div>\n";
 
-			my $file = $diffinfo->{'from_file'};
-			$file  ||= $diffinfo->{'file'};
-			$file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash_parent,
-			                               hash=>$diffinfo->{'from_id'}, file_name=>$file),
-			                -class => "list"}, esc_html($file));
-			$patch_line =~ s|a/.*$|a/$file|g;
-			print "<div class=\"diff from_file\">$patch_line</div>\n";
+				$patch_line = <$fd>;
+				chomp $patch_line;
 
-			$patch_line = <$fd>;
-			chomp $patch_line;
+				#$patch_line =~ m/^+++/;
+				if ($to{'name'}) {
+					my $qq = $to{'quoted'} ? '&quot;' : '';
+					my $from_link = $cgi->a({-href=>$to{'href'},-class=>"list"},
+					                        esc_html($to{'name'}));
+					$patch_line =~ s!["]?b/.*$!${qq}b/$from_link${qq}!;
+				}
+				print "<div class=\"diff to_file\">$patch_line</div>\n";
 
-			#$patch_line =~ m/^+++/;
-			$file    = $diffinfo->{'to_file'};
-			$file  ||= $diffinfo->{'file'};
-			$file = $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
-			                               hash=>$diffinfo->{'to_id'}, file_name=>$file),
-			                -class => "list"}, esc_html($file));
-			$patch_line =~ s|b/.*|b/$file|g;
-			print "<div class=\"diff to_file\">$patch_line</div>\n";
+			}
 
 			next LINE;
 		}
-		next LINE if $in_header;
 
 		print format_diff_line($patch_line);
 	}
-- 
1.4.3.3
Jakub Narebski· Oct 30, 2006, 00:34 UTC · re: Jakub Narebski · lore

Re: [PATCH/RFC (take 2)] gitweb: New improved patchset view

Few other questions, probably to be adressed in the future patches, and not added to this one.

0. git-ls-tree and git-diff-tree without -z does quote not only !isprint 
characters like LF '\n' and non-space whitespace characters like TAB 
'\t' (and of course quoting characters '\' and '"'), but for example 
also UTF-8 characters. See for example git-ls-tree output for 
gitweb/test directory. This screws somewhat idea how we should treat 
filenames which are quoted.

[BTW. How git should deal with being deployed in the environment where filesystem pathnames coding might not be UTF-8, and console (terminal) coding might be not UTF-8?]

1. Current version doesn't display empty patches (i.e. pure rename and 
mode change combinations) and doesn't provide links to them from 
difftree. This is legacy of old /usr/bin/diff using code, which did not 
generated extended diff header, which is only output for "empty 
patches". Should we change this, or leave as is?
2. Schould we change syntax highlighting of chunk header line, namely 
changing slightly syntax coloring of "in which function are we" part of 
chunk header?
3. Should we make from-range/to-range in chunk header hyperlink to the 
start of given bunch of lines in appropriate file? Or perhaps to the 
middle of the bunch of lines? Or to first changed line (omitting 
context)?
-- 
Jakub Narebski
Junio C Hamano· Oct 30, 2006, 01:12 UTC · re: Jakub Narebski · lore

Re: [PATCH/RFC (take 2)] gitweb: New improved patchset view

Jakub Narebski <jnareb@gmail.com> writes:
Show 5 quoted lines
> Few other questions, probably to be adressed in the future patches, and 
> not added to this one.
>
> 0. git-ls-tree and git-diff-tree without -z does quote not only ...
> also UTF-8 characters.
I've already mentioned this in an earlier message to you:
	Message-ID: <7v3b972bzq.fsf@assigned-by-dhcp.cox.net>
Let's illustrate what I mean by an untested patch; this does:
 0. Use explicitly "unsigned char" so that (ch < ' ') does not
    catch bytes in 0x80- range.  The original meant to catch the
    control characters only so this is a bugfix;
 1. We still worry about control characters in 0x80-0x9f range;
    if there are some, that is not a valid UTF-8 string (or
    other encodings that is compatible with ASCII), and quoting
    only these bytes and not quoting 0xa0- range can result
    in letters chopped in the middle, so we would quote all
    bytes in 0xa0- range when we have them;
 2. Otherwise we do not quote bytes in 0xa0- range.
-- >8 --
Show changes to quote.c +19 −6
diff --git a/quote.c b/quote.c
index ee7d62c..4f086fb 100644
--- a/quote.c
+++ b/quote.c
@@ -199,18 +199,32 @@ static int quote_c_style_counted(const c
 
 #define EMITQ() EMIT('\\')
 
-	const char *sp;
-	int ch, count = 0, needquote = 0;
+	const unsigned char *name_u = (const unsigned char *)name;
+	const unsigned char *sp;
+	int ch, count = 0, needquote = 0, has_high_ctrl = 0;
+
+	/* Check if we have control character in 0x80-0x9f range */
+	for (sp = name_u; sp < name_u + namelen; sp++) {
+		ch = *sp;
+		if (!ch)
+			break;
+		if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
+		    (ch == 0177) || (ch == 0377))
+			needquote = 1;
+		else if (0x80 <= ch && ch <= 0x9f)
+			needquote = has_high_ctrl = 1;
+	}
 
 	if (!no_dq)
 		EMIT('"');
-	for (sp = name; sp < name + namelen; sp++) {
+
+	for (sp = name_u; sp < name_u + namelen; sp++) {
 		ch = *sp;
 		if (!ch)
 			break;
 		if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
-		    (ch == 0177) || (ch == 0377)) {
-			needquote = 1;
+		    (ch == 0177) ||
+		    (has_high_ctrl && 0x80 <= ch)) {
 			switch (ch) {
 			case '\a': EMITQ(); ch = 'a'; break;
 			case '\b': EMITQ(); ch = 'b'; break;
-- 8< --

> 1. Current version doesn't display empty patches (i.e. pure rename and 
> mode change combinations) and doesn't provide links to them from 
> difftree. This is legacy of old /usr/bin/diff using code, which did not 
> generated extended diff header, which is only output for "empty 
> patches". Should we change this, or leave as is?

I think this needs to be fixed.

> 2. Schould we change syntax highlighting of chunk header line, namely 
> changing slightly syntax coloring of "in which function are we" part of 
> chunk header?

Probably matching "git diff --color" would be sensible; by
following what has already been done, you do not have to think
about what to color and how yourself.

> 3. Should we make from-range/to-range in chunk header hyperlink to the 
> start of given bunch of lines in appropriate file? Or perhaps to the 
> middle of the bunch of lines? Or to first changed line (omitting 
> context)?

I do not see what usage pattern this link would help.  Care to
explain a bit better?
Jakub Narebski· Oct 30, 2006, 01:21 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC (take 2)] gitweb: New improved patchset view

Junio C Hamano wrote:
Show 8 quoted lines
> Jakub Narebski <jnareb@gmail.com> writes:
>> 3. Should we make from-range/to-range in chunk header hyperlink to the 
>> start of given bunch of lines in appropriate file? Or perhaps to the 
>> middle of the bunch of lines? Or to first changed line (omitting 
>> context)?
> 
> I do not see what usage pattern this link would help.  Care to
> explain a bit better?
For example for the following header
Show changes to _gitweb/gitweb.perl_ +0 −0
diff --git _a/gitweb/gitweb.perl_ _b/gitweb/gitweb.perl_
index _cbab3c9_.._a5a140c_ 100755
--- a/_gitweb/gitweb.perl_
+++ b/_gitweb/gitweb.perl_
@@ _-1255,9_ _+1255,12_ @@ sub parse_difftree_raw_line {

The '-1255,9' would be link to older version of gitweb/gitweb.perl file,
directly to the line #1255 (or to first changed line, or to the middle
of the chunk i.e. 1255+9/2 line).

The '+1255,12' would be link to newer version of file, to line 1255.
-- 
Jakub Narebski

← back to recent threads