Extension talk:GeSHiHighlight

From mediawiki.org
Latest comment: 13 years ago by DimitryPolivaev in topic How to enable download of the embedded code
The following discussion has been transferred from Meta-Wiki.
Any user names refer to users of that site, who are not necessarily users of MediaWiki.org (even if they share the same username).

The instructions state

 Don't forget to include GeSHi also: <php>include_once("geshi.php");</php>

But it doesn't say WHERE to include this. Any ideas? Geshi seems to be working even though I skipped that particular instruction, except for some problems with the display of the text below the text entry area (where it says DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION!)

bad displayed page[edit]

I changed the code a bit, with this you don't need to rename anything.

# you want to change the below three lines

define("GESHI_PATH","../../include/geshi/geshi");// definition where are stored geshi language parsing files
require_once(GESHI_PATH."/../geshi.php"); // i assume geshi.php is in the parent directory of the language files
define("_LANG_DEFAULT", "java");

# ok, end of editing :)
function wfSyntaxExtension() {
        global $wgParser, $lang_default;
        $langArray = geshi_list_languages(GESHI_PATH);
        foreach ( $langArray as $lang ){
                if ($lang == "") continue;
                $wgParser->setHook('code='.$lang,
                        create_function(
                                '$text',
                                        '$geshi = new GeSHi(rtrim(ltrim($text,"\n\r")), ' ."$lang". ', GESHI_PATH);
                                        return $geshi->parse_code();'
                        )
                );
        }
        $wgParser->setHook('code',
		create_function(
			'$text',
				'$geshi = new GeSHi(rtrim(ltrim($text,"\n\r")), _LANG_DEFAULT, GESHI_PATH);
				return $geshi->parse_code();'
			)
        );
}

With this, you can either use <code></code> for the default language or <code=language></code=language> to specify a language.

Camel Case Option[edit]

For languages that are not case sensitive it is nevertheless nice to grant a uniform way of casing keywords through a whole wiki. A GeSHi language file could define a number of keywords written in camel case: for example GetType, SetRecord....

Users often do not comply to the standards and write with mixed case: gETtype, setrEcord.... It doesn't look nice, even if the code might be nevertheless valid.

The patch below defines a new constant in geshi.php: GESHI_CAPS_REPLACE and implements it for replacing the keywords with the corresponding word found in the stored array.

In the geshi.php file find the declaration of the capitalization constants:

// Capatalisation constants
/** Lowercase keywords found */
define('GESHI_CAPS_NO_CHANGE', 0);
/** Uppercase keywords found */
define('GESHI_CAPS_UPPER', 1);
/** Leave keywords found as the case that they are */
define('GESHI_CAPS_LOWER', 2);

add the following line:

define('GESHI_CAPS_REPLACE', 3);

Find the function function change_case ($instr) and replace it with the following:

function change_case ($instr)
	{
		if ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_UPPER) {
			return strtoupper($instr);
		} elseif ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_LOWER) {
			return strtolower($instr);
			
		/************************
		* Orso B. Schmid 01 Jan 2007
		* added support for camelCase keywords:
		* the found keywords will be replaced with the items of the array 
		*/
		} elseif ($this->language_data['CASE_KEYWORDS'] == GESHI_CAPS_REPLACE) {
			foreach ($this->language_data['KEYWORDS'] as $nr => $wordset) {
				$allwords = explode(' ', strtolower(implode(' ', $wordset)));
				if (in_array(strtolower($instr), $allwords)) {
					return $wordset[array_search(strtolower($instr), $allwords)];
				}
			}
		}
		/************************ */
		return $instr;
	}

The new option should be called in the language file(s):

$language_data = array (
	...
	'CASE_KEYWORDS' => GESHI_CAPS_REPLACE,
	....
)

Real code tag support[edit]

The code tag is not truly supported under the last stable version of GeSHi, currently 1.0.7.16. Whatever you do, the code tag converts into block (turns into pre in the html), upsetting a whole wiki content, moreover the classes are not applied to it. It is probably useless, since GeSHi will be updated soon, but there is a fast fix for displaying code tags correctly as inline elements and classes be applied.

In order to achieve this you can modify geshi.php 1.0.7.16:

  1. add a new html container: new constant: GESHI_HEADER_CODE
  2. update the function function set_header_type ($type)
  3. Implement the constant in the function function header ()
  4. Implement the constant in the function function footer ()
Note
this patch in only tested for the version 1.0.7.16!

Add a new constant GESHI_HEADER_CODE[edit]

Find the line where the html containers are defined: // Container HTML type and add the following line:

define('GESHI_HEADER_CODE', 3);

Update header type[edit]

Find the function function set_header_type ($type) and replace the line

if (GESHI_HEADER_DIV != $type && GESHI_HEADER_PRE != $type && GESHI_HEADER_NONE != $type) {

with the line:

if (GESHI_HEADER_DIV != $type && GESHI_HEADER_PRE != $type && GESHI_HEADER_NONE != $type && GESHI_HEADER_CODE != $type) {

Implement in the function 'header'[edit]

Find the function function header () and replace the block:

// Work out what to return and do it
		if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
			if ($this->header_type == GESHI_HEADER_PRE) {
				return "<pre$attributes>$header<ol$ol_attributes>";
			} elseif ($this->header_type == GESHI_HEADER_DIV) {
				return "<div$attributes>$header<ol$ol_attributes>";
			}
		} else {
			if ($this->header_type == GESHI_HEADER_PRE) {
				return "<pre$attributes>$header";
			} elseif ($this->header_type == GESHI_HEADER_DIV) {
				return "<div$attributes>$header";
			}
		}

With the block:

// Work out what to return and do it
		if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
			if ($this->header_type == GESHI_HEADER_PRE) {
				return "<pre$attributes>$header<ol$ol_attributes>";
			} elseif ($this->header_type == GESHI_HEADER_DIV) {
				return "<div$attributes>$header<ol$ol_attributes>";
			} 
			
		} else {
			if ($this->header_type == GESHI_HEADER_PRE) {
				return "<pre$attributes>$header";
			} elseif ($this->header_type == GESHI_HEADER_DIV) {
				return "<div$attributes>$header";
			}
			# Orso B. Schmid 01 Jan 2007: fast fix for <code> tag:
			elseif ($this->header_type == GESHI_HEADER_CODE) {
				return "<code$attributes>$header";
			}
		}

Implement in the function 'footer'[edit]

Find the function function footer () and replace the block:

if ($this->header_type == GESHI_HEADER_DIV) {
			if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
				return "</ol>$footer_content</div>";
			}
			return "$footer_content</div>";
		} else {
			if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
				return "</ol>$footer_content<//pre>";
			}
			return "$footer_content<//pre>";
		}

with the block:

if ($this->header_type == GESHI_HEADER_DIV) {
			if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
				return "</ol>$footer_content</div>";
			}
			return "$footer_content</div>";
		} elseif ($this->header_type == GESHI_HEADER_PRE) {
			if ($this->line_numbers != GESHI_NO_LINE_NUMBERS) {
				return "</ol>$footer_content<//pre>";
			}
			return "$footer_content<//pre>";
		} 
		
		# Orso B. Schmid 01 Jan 2007: fast fix for <code> tag:
		else {
			return "$footer_content</code>";
		}

Please replace the // with / in the pre tag! It seems that it is not possible to escape an ending pre tag within a pre tag!!!!!

Use the constant GESHI_HEADER_CODE[edit]

Now you can call your GeSHi objects in GeSHihiglight as follows, specifying GESHI_HEADER_CODE for code tags elements. In the example below two new tags are created for every installed language file: a code=... and a pre=... tag. For all created geshi objects classes are enabled. Remove what you don't need. Or add other options as explained in the official GeSHi documentation

You can use pre or div or now code according to your needs. If you specify a default for code it remains now inline.

It is advisable to remove unused language files.

function wfSyntaxExtension() {
	global $wgParser, $lang_default;
	$langArray = geshi_list_languages(GESHI_PATH);
	foreach ( $langArray as $lang ){
		if ($lang == "") continue;
			
		# use GESHI_HEADER_CODE to preserve inline code.
		$wgParser->setHook('code='.$lang,
			create_function(
				'$text',
				'$geshi = new GeSHi(rtrim(ltrim($text,"\n\r")), ' ."$lang". ', GESHI_PATH);
				$geshi->set_header_type(GESHI_HEADER_CODE);
				$geshi->enable_classes(true);
				return $geshi->parse_code();'
			)
		);
		
		# use GESHI_HEADER_PRE or GESHI_HEADER_DIV for block elements.
		$wgParser->setHook('pre='.$lang,
			create_function(
				'$text',
				'$geshi = new GeSHi(rtrim(ltrim($text,"\n\r")), ' ."$lang". ', GESHI_PATH);
				$geshi->set_header_type(GESHI_HEADER_PRE);
				$geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS, 1);
				$geshi->enable_classes(true);
				return $geshi->parse_code();'
			)
		);
			
	}
		
	$wgParser->setHook('code',
		create_function(
			'$text',
			'$geshi = new GeSHi(rtrim(ltrim($text,"\n\r")), _LANG_DEFAULT, GESHI_PATH);
			$geshi->set_header_type(GESHI_HEADER_CODE);
			$geshi->enable_classes(true);
			return $geshi->parse_code();'
		)
	);

}

I'm no PHP programmer, so the patch most likely can be optimized. It works fine under MediaWiki 1.8.2.

--Orso B. Schmid 06:50, 3 January 2007 (UTC)Reply

How to enable download of the embedded code[edit]

I extended GeSHiHighlight so that each code fragment can be given a button to download it as a file. You can see an example on page http://freeplane.sourceforge.net/wiki/index.php/Scripting:_Example_scripts .

Following modifications are required:

file download.php with following content should be uploaded into extensions/geshi

<?php
	header("Pragma: no-cache");
	header("Expires: 0");
	if (isset($_POST["text"]) && isset($_POST["filename"])) {
	header("Content-type: application/octet-stream");
	header("Content-Disposition: attachment; filename=" . $_POST["filename"]);
	echo urldecode($_POST["text"]);
	}
	else{
		echo "Data not found";
	}
?>

File GeSHiHighlight.php is modified to consider the new argument

function wfSyntaxExtension() {                                                                                                                                 
        global $wgParser, $wgVersion;

        $langArray = array(...);

        if ( version_compare( $wgVersion, "1.5" ) >= 0 ) { 
        //If version 1.5 or above, $attrib param is included
                foreach ( $langArray as $lang ){                                                                                                                                                                                              
                        $wgParser->setHook( $lang, create_function( '$text,$attrib', 
                                    'return wfSyntaxCode("' . $lang . '", $text, $attrib);'));
                        $wgParser->setHook( $lang.'-file', create_function( '$file_name,$attrib', 
                                    'return wfSyntaxFile("' . $lang . '", $file_name);'));
                }
        } else {
                foreach ( $langArray as $lang ){                                                                                                                                                                                              
                        $wgParser->setHook( $lang, create_function( '$text', 
                                   'return wfSyntaxCode("' . $lang . '", $text, array());'));
                        $wgParser->setHook( $lang.'-file', create_function( '$file_name', 
                                   'return wfSyntaxFile("' . $lang . '", $file_name);'));
                }
        }
}

function wfSyntaxCode($lang, $text, $args) {
		global $wgScriptPath;
		$trimmedText = trim($text);
        $geshi = new GeSHi($trimmedText, $lang, "extensions/geshi"); 
        $html = wfSyntaxDefaults($geshi); 
        if(isset($args["name"])){
			$encodedText = urlencode($trimmedText);
			$filename = $args["name"]. "." . $lang;
			$form = <<<EOFORM
<p></p><code>$filename</code></p>
<form action="$wgScriptPath/extensions/geshi/download.php" method="post">
<input type="hidden" name="text" value="$encodedText" />
<input type="hidden" name="filename" value="$filename" />
<input type="submit" value="download script" />
</form>
EOFORM;
			return $form.$html;
		}
		else{
			return $html;
		}
}

DimitryPolivaev 20:44, 5 January 2011 (UTC)Reply