Extension:GeSHiCodeTag

About
project: GeSHiCodeTag

version: 1.6

update: 05/09/2007

author: Paul Nolasco

email: paul516@gmail.com

site: http://www.wikics.org

description: A tag to create a syntax-highlighted code using GeSHi

Introduction
I've been searching for a good syntax-highlighting code extension for MediaWiki but unfortunately I can't find one that fit my needs. So I decided to just create one myself since I'll also be using it heavily on my site. I also wrote the code as readable and customizale as possible so you can easily extend its features. Feel free to email me for questions/comments/suggestions/errors. Hope you all like my first (and hopefully not the last) MediaWiki extension!

README
Features:
 * Two types of code tags: simple and advanced.
 * Ability to list all languages supported by GeSHi.
 * Ability to disable/enable the code tags
 * Extendability and readability of the code.

Requirements:
 * GeSHi

Tested on: (If you've tested it and it's working on a different version please add it here! Thanks!)
 * MediaWiki 1.9.3, 1.8.2, 1.7.1, 1.6.8, 1.5.7
 * GeSHi-1.0.7.17, 1.0.7.12
 * PHP 5.2.1 5.1.4, 5.1.2

Instructions:

include("extensions/GeshiCodeTag.php");
 * 1) Download Geshi, extract it and place the entire folder content under yourWikiSite/extensions/
 * 2) Copy the GeshiCodeTag source and save it as GeshiCodeTag.php (Note: Be sure to change the $languagesPath depending on your directory)
 * 3) Place GeshiCodeTag.php to yourWikiSite/extensions/
 * 4) Add the include tag right before $wgSiteName of yourWikiSite/LocalSettings.php
 * 1) GeSHiCodeTag extension

'''That's it! Copy the "Tag Examples" below to see if it's working correctly'''

Usage
There are two code tags that you can use:


 * 1) Simple Tag Format:      <'languages'>source code here
 * 2) Advanced Tag Format:

Tag Examples

- simple code tag echo "Hello World";

- advanced code tag

- advanced code tag with line numbers

- default code tag

- display a list of supported languages

DEMO: Here's the result of all the examples above http://www.wikics.org/GeshiCodeTag_Samples

GeSHiCodeTag
<?php


 * 1) GeshiCodeTag.php
 * 2) version 1.6
 * 3) Paul Nolasco
 * 4) Paul516@gmail.com
 * 5) http://www.wikics.org/
 * 1) Paul516@gmail.com
 * 2) http://www.wikics.org/

// change directory accordingly include_once('GeSHi-1.0.7.12/geshi.php'); $languagesPath = "extensions/GeSHi-1.0.7.12/geshi";

// 1 - ENABLED, 0 - DISABLED $codeTag["simple"] = 1;                      // ex. echo $codeTag["advanced"]["mode"] = 1;            // ex. echo // extra options /*		strict mode - http://qbnz.com/highlighter/geshi-doc.html#using-strict-mode ex. " /> $codeTag["advanced"]["strict"] = 0;



$wgExtensionFunctions[] = "ExtensionCodeTag"; $wgExtensionCredits['parserhook'][] = array(        'name' => 'GeSHiCodeTag',         'author' => 'Paul Nolasco',         'url' => 'http://www.wikics.org/', ); $languages = array;

function ExtensionCodeTag {       global $wgParser, $codeTag, $languages;

ReadLanguages;

if($codeTag["advanced"]["mode"]) $wgParser->setHook('code', 'AdvancedCodeTag'); $languagesPath = 'extensions/geshi/geshi'; if($codeTag["simple"]) foreach($languages as $lang) {                    $wgParser->setHook($lang,                                   create_function( '$source', 'global $languagesPath; $geshi = new GeSHi($source,\'' . $lang . '\', $languagesPath); return $geshi->parse_code;' ));               }       }

function ReadLanguages {              global $languages, $languagesPath; $dirHandle = opendir($languagesPath) or die("ERROR: Invalid directory path - [$languagesPath], Modify the value of \$languagesPath'"); $pattern = "^(.*)\.php$"; while ($file = readdir($dirHandle)) {                      if( eregi($pattern, $file) ) $languages[] = eregi_replace($pattern, "\\1", $file); }       closedir($dirHandle); }

function AdvancedCodeTag ($source, $settings){

global $languages, $languagesPath, $codeTag; $language = array_shift($settings);     // [arg1] $isNumbered = array_shift($settings);   // [arg2]

// [arg1] if($language == '') $language='text';                        // bugfix: to work for existing tags, simply use "text" if($language == "list")                                                   // list all languages supported return " List of supported languages for '''Geshi ". GESHI_VERSION. "''': "                  . implode(" ", $languages); if($language != "" && !in_array($language, $languages))             // list languages if invalid argument return " Invalid language argument, \"" . $language . "\", select one from the list: " . implode(" ", $languages); // set geshi $geshi = new GeSHi(trim($source), $language, $languagesPath); $geshi->enable_strict_mode($codeTag["advanced"]["strict"]);

// [arg2] if($isNumbered == "n")                                                             // display line numbers $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); /*         Add more GeSHi features below http://qbnz.com/highlighter/geshi-doc.html */ 		                                                          // removes newlines replaces with

return str_replace("\n",' ', $geshi->parse_code); } ?>

ChangeLog

 * Added changes suggested by Jonyo in the Discussion. It allows GeshiCodeTag to be interleaved with a list. --Paul516 08:17, 9 May 2007 (UTC)
 * Add default language "text" to satisfy legacy wiki code with -tag. --Mstolt 08:18, 11 April 2007 (UTC)
 * Removed strict mode in the default settings. --Paul516 18:31, 10 November 2006 (UTC)
 * Added strict mode by default to Advanced Mode of GeshiCodeTag --Paul516 04:31, 16 September 2006 (UTC)
 * Trims whitespace at beginning and end of the source code. --Paul516 09:00, 10 September 2006 (UTC)
 * Added feature: If a user enters an invalid language argument it'll return a list of the supported languages. --Paul516 05:59, 1 September 2006 (UTC)

Todo List

 * Create a Mediawiki toobar icon for GeshiCodeTag and show how to add it.

Highlighting entire articles
The only problem with the code-wrapped-in-tags solution is that articles containing code that is to be directly executed can't include GeSHi code tags without violating the language's syntax rules, but this problem can be easily fixed by a quick hack that we use on our wiki which I've included below.
 * A GeSHiCodeTag hack by Nad, see GeSHi for more details

Another problem is that we'd often like the ability to use MediaWiki templates even if the content is code, for example when defining LocalSettings articles by transcluding various extension code from other articles. So I've also added an extra line of code into the GeSHi extension before it parses the content to achieve this:

The syntax
The hack allows template syntax to be used to make the entire article be rendered by the GeSHi parser. The templates expand to nothing, so they can be placed anywhere in the article without affecting its execution (if the raw article is requested, templates=expand will need to be included in the query-string to make the template reduce to nothing). It's probably best to put the template in a comment so that the execution is not affected even if templates do not expand. Here's an example: print "bar";
 * 1) { {perl}}

Implementing the hack
First add a few extra lines after the GeSHi include statement to allow the tags to be added before parsing if a language template is transcluded. Here's the updated include line: include('extensions/GeSHiCodeTag.php'); $wgHooks['ParserBeforeStrip'][] = 'GeSHi'; function GeSHi(&$parser, &$text, &$strip_state) { if (preg_match('/\\{\\{(php|perl|c|actionscript|javascript|css)\\}\\}/i',$text,$m)) $text = "\n$text\n"; return true; } Templates or variables must be added which expand to nothing so they don't render as a red link, (my ones look like this example). Also an extra line must be added to the GeSHiCodeTag.php file just before the geshi object is instantiated in the hook function to force the templates to expand.

Change the following block of code; create_function( '$source',                           '$geshi = new GeSHi($source,'. $lang. ', $languagesPath);                           return $geshi->parse_code;'                     )); to  create_function( '$source', '$source = trim($GLOBALS["wgParser"]->replaceVariables($source)); #<- This line has been added $geshi = new GeSHi($source,' . $lang . ', $languagesPath); return $geshi->parse_code;' ));

Issues

 * Mediawiki version less than 1.5 will only work in Simple Mode since older version doesn't accept argument on tags
 * Mediawiki version 1.5.7 - the "div.php" lang definition errantly highlights the mediawiki  copyrightwarning  system message

Alternative
Allthough this extention works very well there seems to be a more active version of basically the same functionality, this is already in the Extension Matrix: http://www.mediawiki.org/wiki/Extension:SyntaxHighlight_GeSHi

Discussion
Click here for any questions/comments/suggestions regarding GeSHiCodeTag