From b331fe54762770c647b8f95c8f5b16004c6120da Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 27 Apr 2010 21:34:44 +0200 Subject: [PATCH 1/2] gitweb: Syntax highlighting support It requires the 'highlight' program to do all the heavy-lifting. This is loosely based on Daniel Svensson's and Sham Chukoury's work in gitweb-xmms2.git (it cannot be cherry-picked, as gitweb-xmms2 first forked wildly, then not contributed back, and then went stale). [jn: cherry picked from bc1ed6aafd9ee4937559535c66c8bddf1864bec6 in http://repo.or.cz/w/git/dscho.git, with a few changes] Signed-off-by: Johannes Schindelin Signed-off-by: Jakub Narebski Acked-by: Petr Baudis Signed-off-by: Junio C Hamano --- gitweb/gitweb.css | 18 +++++++++++++ gitweb/gitweb.perl | 65 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index 50067f2e0d..4132aabcdb 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -572,3 +572,21 @@ span.match { div.binary { font-style: italic; } + +/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */ + +/* Highlighting theme definition: */ + +.num { color:#2928ff; } +.esc { color:#ff00ff; } +.str { color:#ff0000; } +.dstr { color:#818100; } +.slc { color:#838183; font-style:italic; } +.com { color:#838183; font-style:italic; } +.dir { color:#008200; } +.sym { color:#000000; } +.line { color:#555555; } +.kwa { color:#000000; font-weight:bold; } +.kwb { color:#830000; } +.kwc { color:#000000; font-weight:bold; } +.kwd { color:#010181; } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index c356e95f18..de18ebf301 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -227,6 +227,36 @@ BEGIN # Leave it undefined (or set to 'undef') to turn off load checking. our $maxload = 300; +# syntax highlighting +our %highlight_type = ( + # match by basename + 'SConstruct' => 'py', + 'Program' => 'py', + 'Library' => 'py', + 'Makefile' => 'make', + # match by extension + '\.py$' => 'py', # Python + '\.c$' => 'c', + '\.h$' => 'c', + '\.cpp$' => 'cpp', + '\.cxx$' => 'cpp', + '\.rb$' => 'ruby', + '\.java$' => 'java', + '\.css$' => 'css', + '\.php3?$' => 'php', + '\.sh$' => 'sh', # Bash / shell script + '\.pl$' => 'pl', # Perl + '\.js$' => 'js', # JavaScript + '\.tex$' => 'tex', # TeX and LaTeX + '\.bib$' => 'bib', # BibTeX + '\.x?html$' => 'xml', + '\.xml$' => 'xml', + '\.awk$' => 'awk', + '\.bat$' => 'bat', # DOS Batch script + '\.ini$' => 'ini', + '\.spec$' => 'spec', # RPM Spec +); + # You define site-wide feature defaults here; override them with # $GITWEB_CONFIG as necessary. our %feature = ( @@ -445,6 +475,19 @@ BEGIN 'javascript-actions' => { 'override' => 0, 'default' => [0]}, + + # Syntax highlighting support. This is based on Daniel Svensson's + # and Sham Chukoury's work in gitweb-xmms2.git. + # It requires the 'highlight' program, and therefore is disabled + # by default. + + # To enable system wide have in $GITWEB_CONFIG + # $feature{'highlight'}{'default'} = [1]; + + 'highlight' => { + 'sub' => sub { feature_bool('highlight', @_) }, + 'override' => 0, + 'default' => [0]}, ); sub gitweb_get_feature { @@ -5346,6 +5389,7 @@ sub git_blob { open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash or die_error(500, "Couldn't cat $file_name, $hash"); my $mimetype = blob_mimetype($fd, $file_name); + # use 'blob_plain' (aka 'raw') view for files that cannot be displayed if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) { close $fd; return git_blob_plain($mimetype); @@ -5353,6 +5397,25 @@ sub git_blob { # we can have blame only for text/* mimetype $have_blame &&= ($mimetype =~ m!^text/!); + my $have_highlight = gitweb_check_feature('highlight'); + my $syntax; + if ($have_highlight && defined($file_name)) { + my $basename = basename($file_name, '.in'); + foreach my $regexp (keys %highlight_type) { + if ($basename =~ /$regexp/) { + $syntax = $highlight_type{$regexp}; + last; + } + } + + if ($syntax) { + close $fd; + open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ". + "highlight --xhtml --fragment -t 8 --syntax $syntax |" + or die_error(500, "Couldn't open file or run syntax highlighter"); + } + } + git_header_html(undef, $expires); my $formats_nav = ''; if (defined $hash_base && (my %co = parse_commit($hash_base))) { @@ -5404,7 +5467,7 @@ sub git_blob { $line = untabify($line); printf "\n", - $nr, $nr, $nr, esc_html($line, -nbsp=>1); + $nr, $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1); } } close $fd From 592ea4173af6b445042d74b989762fd41aecdf4c Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 27 Apr 2010 21:34:45 +0200 Subject: [PATCH 2/2] gitweb: Refactor syntax highlighting support This refactoring (adding guess_file_syntax and run_highlighter subroutines) is meant to make it easier in the future to add support for other syntax highlighing solutions, or make it smarter by not re-running `git cat-file` second time. Instead of looping over list of regexps (keys of %highlight_type hash), make use of the fact that choosing syntax is based either on full basename (%highlight_basename), or on file extension (%highlight_ext). Add some basic test of syntax highlighting (with 'highlight' as prerequisite) to t/t9500-gitweb-standalone-no-errors.sh test. While at it make git_blob Perl style prettier. Signed-off-by: Jakub Narebski Acked-by: Petr Baudis Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 116 ++++++++++++++----------- t/t9500-gitweb-standalone-no-errors.sh | 29 +++++++ 2 files changed, 92 insertions(+), 53 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index de18ebf301..7d9b660463 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -227,36 +227,6 @@ BEGIN # Leave it undefined (or set to 'undef') to turn off load checking. our $maxload = 300; -# syntax highlighting -our %highlight_type = ( - # match by basename - 'SConstruct' => 'py', - 'Program' => 'py', - 'Library' => 'py', - 'Makefile' => 'make', - # match by extension - '\.py$' => 'py', # Python - '\.c$' => 'c', - '\.h$' => 'c', - '\.cpp$' => 'cpp', - '\.cxx$' => 'cpp', - '\.rb$' => 'ruby', - '\.java$' => 'java', - '\.css$' => 'css', - '\.php3?$' => 'php', - '\.sh$' => 'sh', # Bash / shell script - '\.pl$' => 'pl', # Perl - '\.js$' => 'js', # JavaScript - '\.tex$' => 'tex', # TeX and LaTeX - '\.bib$' => 'bib', # BibTeX - '\.x?html$' => 'xml', - '\.xml$' => 'xml', - '\.awk$' => 'awk', - '\.bat$' => 'bat', # DOS Batch script - '\.ini$' => 'ini', - '\.spec$' => 'spec', # RPM Spec -); - # You define site-wide feature defaults here; override them with # $GITWEB_CONFIG as necessary. our %feature = ( @@ -478,8 +448,8 @@ BEGIN # Syntax highlighting support. This is based on Daniel Svensson's # and Sham Chukoury's work in gitweb-xmms2.git. - # It requires the 'highlight' program, and therefore is disabled - # by default. + # It requires the 'highlight' program present in $PATH, + # and therefore is disabled by default. # To enable system wide have in $GITWEB_CONFIG # $feature{'highlight'}{'default'} = [1]; @@ -3198,6 +3168,61 @@ sub blob_contenttype { return $type; } +# guess file syntax for syntax highlighting; return undef if no highlighting +# the name of syntax can (in the future) depend on syntax highlighter used +sub guess_file_syntax { + my ($highlight, $mimetype, $file_name) = @_; + return undef unless ($highlight && defined $file_name); + + # configuration for 'highlight' (http://www.andre-simon.de/) + # match by basename + my %highlight_basename = ( + #'Program' => 'py', + #'Library' => 'py', + 'SConstruct' => 'py', # SCons equivalent of Makefile + 'Makefile' => 'make', + ); + # match by extension + my %highlight_ext = ( + # main extensions, defining name of syntax; + # see files in /usr/share/highlight/langDefs/ directory + map { $_ => $_ } + qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl), + # alternate extensions, see /etc/highlight/filetypes.conf + 'h' => 'c', + map { $_ => 'cpp' } qw(cxx c++ cc), + map { $_ => 'php' } qw(php3 php4), + map { $_ => 'pl' } qw(perl pm), # perhaps also 'cgi' + 'mak' => 'make', + map { $_ => 'xml' } qw(xhtml html htm), + ); + + my $basename = basename($file_name, '.in'); + return $highlight_basename{$basename} + if exists $highlight_basename{$basename}; + + $basename =~ /\.([^.]*)$/; + my $ext = $1 or return undef; + return $highlight_ext{$ext} + if exists $highlight_ext{$ext}; + + return undef; +} + +# run highlighter and return FD of its output, +# or return original FD if no highlighting +sub run_highlighter { + my ($fd, $highlight, $syntax) = @_; + return $fd unless ($highlight && defined $syntax); + + close $fd + or die_error(404, "Reading blob failed"); + open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ". + "highlight --xhtml --fragment --syntax $syntax |" + or die_error(500, "Couldn't open file or run syntax highlighter"); + return $fd; +} + ## ====================================================================== ## functions printing HTML: header, footer, error page @@ -5397,24 +5422,10 @@ sub git_blob { # we can have blame only for text/* mimetype $have_blame &&= ($mimetype =~ m!^text/!); - my $have_highlight = gitweb_check_feature('highlight'); - my $syntax; - if ($have_highlight && defined($file_name)) { - my $basename = basename($file_name, '.in'); - foreach my $regexp (keys %highlight_type) { - if ($basename =~ /$regexp/) { - $syntax = $highlight_type{$regexp}; - last; - } - } - - if ($syntax) { - close $fd; - open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ". - "highlight --xhtml --fragment -t 8 --syntax $syntax |" - or die_error(500, "Couldn't open file or run syntax highlighter"); - } - } + my $highlight = gitweb_check_feature('highlight'); + my $syntax = guess_file_syntax($highlight, $mimetype, $file_name); + $fd = run_highlighter($fd, $highlight, $syntax) + if $syntax; git_header_html(undef, $expires); my $formats_nav = ''; @@ -5465,9 +5476,8 @@ sub git_blob { chomp $line; $nr++; $line = untabify($line); - printf "\n", - $nr, $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1); + printf qq!
%4i %s
\n!, + $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1); } } close $fd diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 63b6b060e6..4f2b9b062b 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -647,4 +647,33 @@ test_expect_success \ gitweb_run "p=.git;a=summary"' test_debug 'cat gitweb.log' +# ---------------------------------------------------------------------- +# syntax highlighting + +cat >>gitweb_config.perl <<\EOF +$feature{'highlight'}{'override'} = 1; +EOF + +highlight --version >/dev/null 2>&1 +if [ $? -eq 127 ]; then + say "Skipping syntax highlighting test, because 'highlight' was not found" +else + test_set_prereq HIGHLIGHT +fi + +test_expect_success HIGHLIGHT \ + 'syntax highlighting (no highlight)' \ + 'git config gitweb.highlight yes && + gitweb_run "p=.git;a=blob;f=file"' +test_debug 'cat gitweb.log' + +test_expect_success HIGHLIGHT \ + 'syntax highlighting (highlighted)' \ + 'git config gitweb.highlight yes && + echo "#!/usr/bin/sh" > test.sh && + git add test.sh && + git commit -m "Add test.sh" && + gitweb_run "p=.git;a=blob;f=test.sh"' +test_debug 'cat gitweb.log' + test_done