Introducing the GeSHi Syntax Highlighter for b2 (Take 2)
[Note: I am reposting this with updated installation instructions and code corrections due to a bug with the hack itself that rendered some of the code meaningless in the original post.]
Yesterday I posted on how I integrated the GeSHi Syntax Highlighter into FlashAnt to highlight AS2. I also mentioned how GeSHi supports over 30 languages. Having already gotten a request for the source -- read on, Richard :) -- and not being one who can leave well enough alone, I spent a little time this morning to clean up the hack and make it generic enough to support any language. Of course, nothing being simple, I was waylaid by an over-anxious slash-adding routine in b2 (which had me doubting my sanity and my PHP server settings), work, email and, quite unexpectedly, smileys :x -- which b2 insists on erroneously calling "smilies!" :roll: (Yes, along the way I have become intimately familiar with the various types of smileys on offer and their codes, so get ready for some smiley spam in future posts!) :mrgreen:
Although I could bore you to death with details of the various issues, suffice to say that I've now gotten the whole thing to work.
So, without further ado, taadaaa..! We now have an official GeSHi Syntax Highlighter hack for b2! :)
I'm releasing it under the GPL license as per the original b2 code.
Instructions for installing the hack:
1. Back-up your site if its not under version control. I take no responsibility if you somehow manage to blow up your computer, infuriate your wife or do something equally nasty to your pet hamster while trying to install this.
2. Add the following configuration information, customizing it for your needs, to the b2config.php file in the root folder of your b2 installation:
//////////////////////////////////////////////////////////////////////// // // Geshi Syntax Highlighter Configuration // Added by Aral Balkan. 17/12/2004 // Comments? Suggestions? Email aral@ariaware.com // Docs, updates: http://flashant.org // //////////////////////////////////////////////////////////////////////// // // The path to your language files // The default configuration assumes that you have a folder called // geshi in the root folder of your b2 installation. // $geshiLanguageFilesPath = 'geshi'; // // Maps the tags used to identify different languages to // the name of the Geshi syntax file and the nicely formatted // human-readable name to be displayed on top of the // highlighted code segment. // // So, for example, with the default settings, you will need // to surround ActionScript 2 code with as2 tags // and PHP code with php tags. Geshi will then // use the syntax rules in geshi/actionscript.php for the former // and geshi/php.php for the latter. The code segments for AS2 // will be preceding with the label "ActionScript:" and for PHP // the label will be "PHP:". // $geshiLanguages = array ( ); // // Should GeSHi use line numbers in the output? (Does not appear // to display on IE but works well in FireFox. Degrades gracefully // in IE.) // $geshiEnableLineNumbers = true; ////////////////////////////////////////////////////////////////////////
3. Add the following lines of code to the top of the b2functions.php file in the b2-include folder:
// Include the GeSHi Syntax Highlighter include_once ('geshi.php');
4. In b2functions.php, again, add the following two functions:
////////////////////////////////////////////////////////////////////// // // GeSHi syntax highlighter module for b2 // // Added by Aral Balkan. 17/12/2004 // Comments? Suggestions? Email aral@ariaware.com // Docs, updates: http://flashant.org // ////////////////////////////////////////////////////////////////////// function syntaxHighlight ( $content ) { // Configuration information from b2config.php global $geshiLanguages; // Highlight each language in turn foreach ( $geshiLanguages as $tag => $languageInfo ) { $content = geshiHighlight ( $content, $tag, $languageInfo[0], $languageInfo[1] ); } return $content; } function geshiHighlight ( $content, $tag, $languageName, $languageDisplayName ) { // Configuration information from b2config.php // Create a GeSHi instance $geshi = new GeSHi('', $languageName, $geshiLanguageFilesPath); $geshi->enable_line_numbers($geshiEnableLineNumbers); // Match the contents of the requested tag // and return them in an array. $preg="/<".$tag.">(.*?)<\/".$tag.">/si"; foreach ($code[1] as $rawSource) { // We don't want smiley faces :) $geshi->set_source( $rawSource ); $highlightedSource = $geshi->parse_code(); // // Got this style from the ActionScript highlighting hack for VBulletin // that we use on the London MMUG web site. Works well for b2! // Should parameterize the style settings into b2config at some point. // For the time being, just alter them here. // $styleHack = '<div style="margin:20px; margin-top:5px">'; $styleHack .= '<div class="smallfont" style="margin- bottom:2px">'.$languageDisplayName.':</div>'; $styleHack .= '<div class="alt2" style="margin:0px; padding:6px; border:1px '; $styleHack .= 'inset; width:420px; height:178px; overflow:auto">'; $highlightedSource = $styleHack . $highlightedSource . '</div></div>'; } // Return the highlighted content return $content; } //////////////////////////////////////////////////////////////////////
5. Replace the convert_smilies method in b2functions.php with the one below. You need to do this so that b2 doesn't make smileys out of your data-type declarations (things like var something:Preloader would otherwise show up with a :P in the middle!) This new method uses a regular expression that is not nearly as greedy as str_replace.
function convert_smilies($content) { if ($use_smilies) { foreach ( $b2smiliestrans as $smilie => $img ) { // Escape characters that have special meaning for RegExp // and build the RegExp. $smilieRegexp = '/((?<=[ (\\t\\n>])|\\r\\n|\\A)'.$smilieRegExp.'((?=[ ,.)!\\t\\n<])|\\r\\n|\\Z)/'; } } return ($content); }
6. Next, in b2edit.php (root folder of your b2 installation), you need to comment out the overly anxious slash adding routine which appears to be left-over code. It should not be necessary as the various methods in b2functions.php all carry out the adding of slashes when necessary. We need to remove this otherwise GeSHi rightly gets confused when it finds code with slashes behind every single and double quote!
You can see the section to be commented out below, with a bit of the surrounding code to put it into context.
<?php $title = "Post / Edit"; /* <Edit> */ // Removed due to conflict with the GeSHi Syntax Highlighter hack. /* function add_magic_quotes($array) { foreach ($array as $k => $v) { if (is_array($v)) { $array[$k] = add_magic_quotes($v); } else { $array[$k] = addslashes($v); } } return $array; } if (!get_magic_quotes_gpc()) { $HTTP_GET_VARS = add_magic_quotes($HTTP_GET_VARS); $HTTP_POST_VARS = add_magic_quotes($HTTP_POST_VARS); $HTTP_COOKIE_VARS = add_magic_quotes($HTTP_COOKIE_VARS); } */ $b2varstoreset = array('action','safe_mode','withcomments','c','posts','poststart','content','edited_post_title','comment_error','profile', 'trackback_url'); for ($i=0; $i<count($b2varstoreset); $i += 1) {
7. Also in b2edit.php, search for "case 'post':" (without the quatation marks). After the $content = format_to_post($content); line, add the following line of code:
8. Next, modify the format_to_post() method in b2functions.php to add the syntax highlighting (see line 4.) It should resemble the code below once you've implemented it:
function format_to_post($content) { // Add Geshi syntax highlighting to code segments $content = syntaxHighlight ( $content ); if ($post_autobr || $comment_autobr) { $content = autobrize($content); } return($content); }
9. Finally, you need to download GeSHi and copy (FTP, etc.) geshi.php and the geshi folder (with the various language files) to the root folder of your b2 installation.
That's it! You can now define custom tags for highlighting a plethora of languages in your posts. GeSHi currently supports Actionscript ADA, Apache Log, ASM, ASP, Bash, C, C for Macs, C#, C++, CAD DCL, CadLisp, CSS, Delphi, HTML, Java, Javascript, Lisp, Lua, NSIS, Objective C, OpenOffice BASIC, Pascal, Perl, PHP, Python, Q(uick)BASIC, Smarty, SQL, VB.NET, Visual BASIC, Visual Fox Pro and XML.
It's now possible to switch from...
class Isnt extends MovieClip { function Isnt () { trace ( "Isn't " ); } }
To, say...
To...
using System; public class Cool { public static void Main() { Console.WriteLine( " cool?" ); } }
Isn't this cool?
I haven't tested the performance hit when you have lots of languages enabled (works fine on four, currently) but it should not be a problem since the code is only executed when you are making a post.
Note that once you've highlighted your code, it will not revert back to its unhighlighted state when you edit the post. If you need to make changes to the code, I suggest you either make a separate post and copy the code from there or copy the whole post, delete it and repost it. I'm going to look into how easy it will be to hack the Preview functionality so that it includes the hack. That should make it easier to edit posts for code updates.
I hope you find this hack useful and please feel free to email me with your comments, suggestions and improvements.