[Home]WikiPatches/SourceHighlight

UseModWiki | WikiPatches | RecentChanges | Preferences

Source Highlight Patch

For a more lightweight implementation, see /SourceHighlight2

Description

This patch uses the GNU source-highlight package (available from http://www.gnu.org/software/src-highlite/). With this patch you can enclose source code snippets between special tags, and have them show up properly highlighted on the page. The html output has the class codefragment. I would add something like this to wiki.css to make the output look neat:

 PRE.codefragment {
     border: 1px solid #CCCCCC;
     background-color: #f5f5f5;
     margin: 4px 8px 4xp 2px;
     padding: 4px 6px;
 }

The tags are <code language> and </code>. The language can be anything that your version of source-highlight supports, e.g. cpp, perl, java, etc.

The $SourceHighlight? config variable must be set to wherever the source-highlight binary is installed. The default is /usr/local/bin/source-highlight.

TODO: The current implementation requests a global lock for the duration of source-highlight. This should be replaced with a smarter locking mechanism.

NOTE: This patch starts a source-highlight process for each piece of hightlighted code in a wiki page. If your server is heavily loaded, use /SourceHighlight2 instead.

The patch


--- wiki.pl	2003-09-11 14:21:02.000000000 +0200
+++ SourceHighlight.pl	2005-10-21 11:38:22.000000000 +0200
@@ -53,7 +53,9 @@
   @IsbnNames @IsbnPre @IsbnPost $EmailFile $FavIcon $RssDays $UserHeader
   $UserBody $StartUID $ParseParas $AuthorFooter $UseUpload $AllUpload
   $UploadDir $UploadUrl $LimitFileUrl $MaintTrimRc $SearchButton 
-  $EditNameLink $UseMetaWiki @ImageSites $BracketImg );
+  $EditNameLink $UseMetaWiki @ImageSites $BracketImg 
+  $SourceHighlight
+  );
 # Note: $NotifyDefault is kept because it was a config variable in 0.90
 # Other global variables:
 use vars qw(%Page %Section %Text %InterSite %SaveUrl %SaveNumUrl
@@ -89,6 +91,7 @@
 $NotFoundPg  = "";              # Page for not-found links ("" for blank pg)
 $EmailFrom   = "Wiki";          # Text for "From: " field of email notes.
 $SendMail    = "/usr/sbin/sendmail";  # Full path to sendmail executable
+$SourceHighlight = "/usr/local/bin/source-highlight"; # GNU sourcehighlight for <CODE>
 $FooterNote  = "";              # HTML for bottom of every page
 $EditNote    = "";              # HTML notice above buttons on edit page
 $MaxPost     = 1024 * 210;      # Maximum 210K posts (about 200K for pages)
@@ -1580,6 +1583,8 @@
     $pageText =~
         s/\<pre\>((.|\n)*?)\<\/pre\>/&StorePre($1, "pre")/ige;
     $pageText =~
+        s/\<code(?:\s+(\w+))?\>((.|\n)*?)\<\/code\>/&StoreCode($2, $1)/ige;
+    $pageText =~
         s/\<code\>((.|\n)*?)\<\/code\>/&StorePre($1, "code")/ige;
     $pageText =~ s/((.|\n)+?\n)\s*\n/&ParseParagraph($1)/geo;
     $pageText =~ s/(.*)<\/p>(.+)$/$1.&ParseParagraph($2)/seo;
@@ -1607,6 +1612,7 @@
     s/\<nowiki\>((.|\n)*?)\<\/nowiki\>/&StoreRaw($1)/ige;
     # The <pre> tag wraps the stored text with the HTML <pre> tag
     s/\<pre\>((.|\n)*?)\<\/pre\>/&StorePre($1, "pre")/ige;
+    s/\<code(?:\s+(\w+))?\>((.|\n)*?)\<\/code\>/&StoreCode($2, $1)/ige;
     s/\<code\>((.|\n)*?)\<\/code\>/&StorePre($1, "code")/ige;
     if ($EarlyRules ne '') {
       $_ = &EvalLocalRules($EarlyRules, $_, !$useImage);
@@ -1894,6 +1900,62 @@
   return &StoreRaw("<$tag>" . $html . "</$tag>");
 }
 
+sub StoreCode {
+  my ($text, $lang) = @_;
+
+  if ($SourceHighlight eq '' || not defined $lang) {
+    return &StorePre($text, 'CODE');
+  }
+
+  &RequestLock();
+
+  $text =~ s/</</g;
+  $text =~ s/>/>/g;
+  $text =~ s/&/&/g;
+  my $this_cmd = "$SourceHighlight -f html -t 4 -s $lang";
+  my $tmp_file = "$TempDir/highlight";
+
+  eval { open( TMP, "> $tmp_file" ) || die $! };
+  if ( $@ ) {
+    &ReleaseLock();
+    return &StoreRaw("Failed to open temp file [$tmp_file] for writing: $@" );
+  }
+  print TMP $text;
+  close( TMP );
+
+  eval { open( CMD, "$this_cmd < $tmp_file |" ) || die $! };
+  if ( $@ ) {
+    &ReleaseLock();
+    return &StoreRaw("Failed to open pipe to command [$this_cmd]: $@" );
+  }
+  my @lines = <CMD>;
+  close( CMD );
+
+  unless (unlink( $tmp_file )) {
+    &ReleaseLock();
+    return &StoreRaw( "Error: cannot delete temp file [$tmp_file]: $@" );
+  }
+
+  &ReleaseLock();
+
+  # Cosmetic: Get rid of lines 1 and 2 (0-based), plus the
+  # next-to-last line
+
+  while ($lines[0] =~ /^(<tt>|<pre>|\s+)*$/i) {
+    splice( @lines, 0, 1 );
+  }
+  while ($lines[scalar @lines - 1] =~ /^(<\/tt>|<\/pre>|\s+)*$/i) {
+       splice( @lines, scalar @lines - 1, 1 );
+  }
+  # splice( @lines, 1, 2 );
+  # splice( @lines, scalar @lines - 2, 1 );
+
+  return &StoreRaw(join( '',
+    qq(<pre class="codefragment">),
+    @lines,
+    qq(</pre>)));
+}
+
 sub StoreHref {
   my ($anchor, $text) = @_;


UngarPeter


UseModWiki | WikiPatches | RecentChanges | Preferences
Edit text of this page | View other revisions | Search MetaWiki
Last edited September 28, 2006 6:51 am by UngarPeter (diff)
Search: