====== Code Syntax PlugIn ====== ---- plugin ---- description: Syntax highlighting with optional line numbers author : Matthias Watermann email : support@mwat.de type : render, syntax lastupdate : 2008-07-22 compatible : 2005-07-13+ depends : conflicts : similar : code tags : cli, code, diff, export, geshi, highlighting, odt, opendocument, openoffice, shell, syntax ---- While writing several pages to document some sour­ce code I noticed that it would be help­ful if there were //line num­bers// added au­to­ma­ti­cally when using the ''%%%%'' tag to high­light the re­spec­tive code fragments. In­ve­sti­ga­ting the un­der­lying //[[http://qbnz.com/highlighter/|GeSHi]]// system((which is used by DokuWiki internally for syntax highlighting)) sho­wed that its line num­be­ring fea­ture was not available for use in Doku­Wiki((And for a good reason, I'd say: It produces a bunch of markup that does not even va­li­date.)). --- Hence I wrote this plugin, which //re­places// and en­han­ces Do­ku­Wiki's builtin "''%%%%''" fea­ture. While I was at it I integrated the algorithms of my older [[diff|Diff plugin]] as well((that one as well was written initially to solve problems with the in some respects rather li­mi­ted //GeSHi//)) -- this way ob­so­le­ting the latter((although both plugins will work side by side without disturbing each other)). --- And after some en­ligh­te­ning((by private mail, directing me to think about CSS styling ...)) I im­ple­men­ted the op­tion to spe­ci­fy an op­tio­nal //hea­der/foo­ter// for a code sec­tion. --- Some time later the [[#Console]] mode, the inclusion of [[#External Files|external]] resources and [[#Open Document Format|ODT]] support followed. So the abstract markup looks like this: {code to highlight} * "''lang''" (if present) specifies the given code's (programming-) language; * "''123''" (if present) specifies the first number to use when numbering the given code's lines; * the first "''%%|%%''" (if present) delimits the first argument(s) from the remaining ones which are used to produce a //header// or //footer// above/below the high­ligh­ted code; * a "''h''" (for //"header"//)((or "''t''" for //"top"//)) following //immediately// the pipe cha­rac­ter cau­ses the remaining "''text''" to get placed //above// the code, a "''f''" (for //"footer"//)((or "''b''" for //"bottom"//)) places the "''text''" below the code (note that this flag is //optional//; if omitted it de­faults to "''f''"); * the "''text''" is used as-is with the additional benefit of get­ting wrapped by an anchor tag which allows for addressing the code from other pages. * the second "''%%|%%''" (if present) delimits the header/footer text; * a "''s''"((for //"show"//, the default)) or "''h''"((for //"hide"//)) character (if present) controls the code block's initial folding state; for more details see the [[#folding_state|Behaviour]] section below. * the "''{code to highlight}''" is either the plain text to process or a pointer to an [[#external_files|external source]]. ===== Usage ===== Backward compatible with DokuWiki's builtin "''%%%%''" [[#Notes|markup]] this plugin pro­vi­des ad­di­tio­nal (op­tio­nal) arguments which can be used to both tur­ning ON the new line num­be­ring fea­ture and specify the first num­ber to use ac­tu­ally when num­bering the lines. As for "''diff''" the optional second argument can be used to give a hint about the diff (//unified//, //context//, //RCS// or //simple//) for­mat. To use syntax highlighting you'll use the "''%%%%''" tag as you're used to do. With­out giving a new argument the output will be just the same as with Doku­Wiki's builtin((After all, the //GeSHi// engine is used very much the same way.)). * ''%%%%\\ some text\\ %%%%'' __//(basic)//__\\ just marks up "''some text''" as preformatted text (w/o any special high­ligh­ting). * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ marks up "''some text''" as preformatted text (w/o any special highlighting) with line numbers star­ting at number ''7''. * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ marks up "''some text''" as preformatted text (w/o any special highlighting) with a footer line of "''A description''". * ''%%%%\\ some text\\ %%%%'' __//(basic)//__\\ turns on HTML highlighting for "''some text''". * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ turns on HTML highlighting for "''some text''" with added line num­bers star­ting with number ''1''. * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ turns on HTML highlighting for "''some text''" and a header line of "''A description:''". * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ turns on HTML highlighting for "''some text''" with added line num­bers star­ting with number ''66'' and a footer line of "''A descrip­tion''". * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ turns on ''diff'' highlighting (autodetecting the patch format). * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ turns on ''diff'' highlighting (assuming an ''unified'' patch format). * ''%%%%\\ some text\\ %%%%'' __//(extended)//__\\ turns on ''diff'' high­ligh­ting (as­su­ming a ''context'' patch format) and a footer line of "''A descrip­tion''". * ''%%%%\\ some console commands capture\\ %%%%'' __//(extended)//__\\ turns on [[#Console|console]] mode with a footer line of "''The shell output''". * ''%%%%\\ extern> %%http://some.where.else.tld/page.html%%\\ %%%%'' __//(extended)//__\\ turns on HTML highlighting for the [[#External Files|external]] "''%%http://some.where.else.tld/page.html%%''" page's source with added line num­bers star­ting with number ''1'' and a header line of "''The example page:''". The entries marked __//(basic)//__ are available with DokuWiki's builtin ''%%%%'' mark­up as well, while those marked __//(extended)//__ are features added by this plugin. So if you neither need nor want any of the latter you won't have to install this plugin but instead get yourself a cup of tea and watch the sunset. And just for the records: The optional line number argument specifies the first //number// to use when numbering the lines but //not// the first code line to show. ==== Examples ==== Please note that you will //not// see any highlighting //here//: This section just shows some use cases with­out actually triggering the activation of the plugin -- even if it was installed ... some text and more This just renders the given preformatted text without any spe­cial high­ligh­ting. However, some text and more will add line numbers in front of each line starting (in this case) with ''1'' (one). var de = function() { return (typeof(window.de) == 'object') ? window.de : {}; }(); This markup will turn on both the JavaScript syntax highlighting and the line num­be­ring star­ting in this case with num­ber ''12'' and place the text "''Listing 2''" below the code block -- pro­du­cing HTML like:
  12:  var de = function() {
  13:      return (typeof(window.de) == 'object') ? window.de : {};
  14:  }();
  

Listing 2

If you'd rather the text //above// the code you'd just insert a "''h''" right after the pipe character i.e. "''%%%%''". Of course, instead of ''javascript'' you may use any other highlighting mode sup­por­ted by //GeSHi// like "''html''" for exam­ple or "''php''". In case a lan­gua­ge is gi­ven which is //not// sup­por­ted by //GeSHi// there won't be any syn­tax high­ligh­ting, of course, but the line num­bers (if re­que­sted) and hea­der/foo­ter li­nes (if re­que­sted) will ap­pear ne­ver­the­less. As men­tio­ned abo­ve be­si­des the line num­be­ring fea­tu­re this plugin pro­vi­des an im­pro­ved high­ligh­ting mode for "''diff''" files (aka "''pat­ches''"). For "''diff''" the second argument can be either __''u''__ (for "//unified//"), __''c''__ (for "//con­text//"), __''n''__ (or __''r''__ for //RCS//) or __''s''__ (for "//simple//") format((Meaning, that line numbering is //not// available for "''diff''". It wouldn't make any sense any­way. Just think about it.)). Although ap­pre­ciated this ar­gu­ment is optional as well. Omitting it will cause the plugin to per­form some ad­di­tio­nal tests to figure out the "''diff''" for­mat ac­tu­ally used. For more in­for­ma­tion see the [[diff#examples|Examples]] sec­tion of the [[diff|Diff]] plugin's doc. To summarize: * Without the new arguments nothing changes from what you're used to know (and get) -- but see the [[#Notes]] section below. * Giving a numeric argument //only// results in preformatted text without high­ligh­ting but line numbering turned on. * Giving just a language argument turns on syntax highlighting w/o line num­bers. * Giving a language //and// a numeric argument turns on syntax highlighting //and// line numbering starting with the given number. * Adding a "''|''", optionally followed by "''h''" or "''f''" and some text will result in a header or footer line attached to the code block (see [[#Behaviour]] below). ===== Installation ===== It's quite easy to integrate this plugin with your DokuWiki: - Download the [[http://dev.mwat.de/dw/syntax_plugin_code.zip|source archive]] (~25KB) and un­pack it in your Doku­Wiki plug­in di­rec­to­ry ''{dokuwiki}/lib/plugins'' (make sure, in­clu­ded sub­di­rec­to­ries are un­packed cor­rect­ly); this will create the di­rec­tory ''{dokuwiki}/lib/plugins/code''. - Make sure both the new direc­tory and the files therein are read­able by the web-server e.g. $> chown apache:apache dokuwiki/lib/plugins/* -Rc You might as well use the [[http://www.dokuwiki.org/plugin:plugin|plugin manager]] for installing or updating this plugin. ===== Plugin Source ===== Here comes the [[http://www.gnu.org/licenses/gpl.html|GPLed]] PHP source((The comments within the [[#Plugin Source|source]] file are suit­able for the OSS [[http://www.stack.nl/~dimitri/doxygen/index.html|doxygen]] tool, a do­cu­men­ta­tion sy­stem for C++, C, Java, Ob­jec­tive-C, Py­thon, IDL and to some ex­tent PHP, C#, and D. --- Since I'm wor­king with dif­fe­rent pro­gram­ming lan­gua­ges it's a great ease to have one tool that handles the docs for all of them.)) for those who'd like to scan be­fore actu­ally in­stal­ling it: syntax_plugin_code.php - A PHP4 class that implements the * DokuWiki plugin for highlighting code fragments. * *

* Usage:
* <code [language startno |[fh] text |[hs]]>...</code> *

 *  Copyright (C) 2006, 2008  M.Watermann, D-10247 Berlin, FRG
 *      All rights reserved
 *    EMail : <support@mwat.de>
 * 
* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either * version 3 of the * License, or (at your option) any later version.
* This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. *
* @author Matthias Watermann * @version $Id: syntax_plugin_code.php,v 1.29 2008/07/22 09:22:47 matthias Exp $ * @since created 24-Dec-2006 */ class syntax_plugin_code extends DokuWiki_Syntax_Plugin { /** * @privatesection */ //@{ /** * Additional markup used with older DokuWiki installations. * * @private * @see _fixJS() */ var $_JSmarkup = FALSE; /** * Indention "text" used by _addLines(). * *

* Note that we're using raw UTF-8 NonBreakable Spaces here. *

* @private * @see _addLines() */ var $_lead = array('', ' ', '  ', '   ', '    ', '     ', '      ', '       '); /** * Section counter for ODT export * * @private * @see render() * @since created 08-Jun-2008 */ var $_odtSect = 0; /** * Prepare the markup to render the DIFF text. * * @param $aText String The DIFF text to markup. * @param $aFormat String The DIFF format used ("u", "c", "n|r", "s"). * @param $aDoc String Reference to the current renderer's * doc property. * @return Boolean TRUE. * @private * @see render() */ function _addDiff(&$aText, &$aFormat, &$aDoc) { // Since we're inside a PRE block we need the leading LFs: $ADD = "\n" . ''; $DEL = "\n" . ''; $HEAD = "\n" . ''; $CLOSE = ''; // Common headers for all formats; // the RegEx needs at least ")#" appended! $DiffHead = '#\n((?:diff\s[^\n]*)|(?:Index:\s[^\n]*)|(?:={60,})' . '|(?:RCS file:\s[^\n]*)|(?:retrieving revision [0-9][^\n]*)'; switch ($aFormat) { case 'u': // unified output $aDoc .= preg_replace( array($DiffHead . '|(?:@@[^\n]*))#', '|\n(\+[^\n]*)|', '|\n(\-[^\n]*)|'), array($HEAD . '\1' . $CLOSE, $ADD . '\1' . $CLOSE, $DEL . '\1' . $CLOSE), $aText); return TRUE; case 'c': // context output $sections = preg_split('|(\n\*{5,})|', preg_replace($DiffHead . ')#', $HEAD . '\1' . $CLOSE, $aText), -1, PREG_SPLIT_DELIM_CAPTURE); $sections[0] = preg_replace( array('|\n(\-{3}[^\n]*)|', '|\n(\*{3}[^\n]*)|'), array($ADD . '\1' . $CLOSE, $DEL . '\1' . $CLOSE), $sections[0]); $c = count($sections); for ($i = 1; $c > $i; ++$i) { $hits = array(); if (preg_match('|^\n(\*{5,})|', $sections[$i], $hits)) { unset($hits[0]); $sections[$i] = $HEAD . $hits[1] . $CLOSE; } else if (preg_match('|^\n(\x2A{3}\s[^\n]*)(.*)|s', $sections[$i], $hits)) { unset($hits[0]); // free mem $parts = preg_split('|\n(\-{3}\s[^\n]*)|', $hits[2], -1, PREG_SPLIT_DELIM_CAPTURE); // $parts[0] == OLD code $parts[0] = preg_replace('|\n([!\-][^\n]*)|', $DEL . '\1' . $CLOSE, $parts[0]); // $parts[1] == head of NEW code $parts[1] = $ADD . $parts[1] . $CLOSE; // $parts[2] == NEW code $parts[2] = preg_replace( array('|\n([!\x2B][^\n]*)|', '|\n(\x2A{3}[^\n]*)|'), array($ADD . '\1' . $CLOSE, $DEL . '\1' . $CLOSE), $parts[2]); if (isset($parts[3])) { // TRUE when handling multi-file patches $parts[3] = preg_replace('|^(\x2D{3}[^\n]*)|', $ADD . '\1' . $CLOSE, $parts[3]); } // if $sections[$i] = $DEL . $hits[1] . $CLOSE . implode('', $parts); } // if // ELSE: leave $sections[$i] as is } // for $aDoc .= implode('', $sections); return TRUE; case 'n': // RCS output // Only added lines are there so we highlight just the // diff indicators while leaving the text alone. $aDoc .= preg_replace( array($DiffHead . ')#', '|\n(d[0-9]+\s+[0-9]+)|', '|\n(a[0-9]+\s+[0-9]+)|'), array($HEAD . '\1' . $CLOSE, $DEL . '\1' . $CLOSE, $ADD . '\1' . $CLOSE), $aText); return TRUE; case 's': // simple output $aDoc .= preg_replace( array($DiffHead . '|((?:[0-9a-z]+(?:,[0-9a-z]+)*)(?:[^\n]*)))#', '|\n(\x26#60;[^\n]*)|', '|\n(\x26#62;[^\n]*)|'), array($HEAD . '\1' . $CLOSE, $DEL . '\1' . $CLOSE, $ADD . '\1' . $CLOSE), $aText); return TRUE; default: // unknown diff format $aDoc .= $aText; // just append any unrecognized text return TRUE; } // switch } // _addDiff() /** * Add the lines of the given $aList to the specified * $aDoc beginning with the given $aStart linenumber. * * @param $aList Array [IN] the list of lines as prepared by * render(), [OUT] FALSE. * @param $aStart Integer The first linenumber to use. * @param $aDoc String Reference to the current renderer's * doc property. * @private * @see render() */ function _addLines(&$aList, $aStart, &$aDoc) { // Since we're dealing with monospaced fonts here the width of each // character (space, NBSP, digit) is the same. Hence the length of // a digits string gives us its width i.e. the number of digits. $i = $aStart + count($aList); // greatest line number $g = strlen("$i"); // width of greatest number while (list($i, $l) = each($aList)) { unset($aList[$i]); // free mem $aDoc .= '' . $this->_lead[$g - strlen("$aStart")] . "$aStart:" . ((($l) && (' ' != $l)) ? " $l\n" : "\n"); ++$aStart; // increment line number } // while $aList = FALSE; // release memory } // _addLines() /** * Internal convenience method to replace HTML special characters. * * @param $aString String [IN] The text to handle; * [OUT] the modified text (i.e. the method's result). * @return String The string with HTML special chars replaced. * @private * @since created 05-Feb-2007 */ function &_entities(&$aString) { $aString = str_replace(array('&', '<', '>'), array('&', '<', '>'), $aString); return $aString; } // _entities() /** * Try to fix some markup error of the GeSHi SHELL highlighting. * *

* The GeShi highlighting for type "sh" (i.e. "bash") is, well, * seriously flawed (at least up to version 1.0.7.20 i.e. 2007-07-01). * Especially handling of comments and embedded string as well as * keyword is plain wrong. *

* This internal helper method tries to solve some minor problems by * removing highlight markup embedded in comment markup. * This is, however, by no means a final resolution: GeSHi obviously * keeps a kind of internal state resulting in highlighting markup * spawing (i.e. repeated on) several lines. * Which - if that state is wrong - causes great demage not by * corrupting the data but by confusing the reader with wrong markup. * The easiest way to trigger such a line spawning confusion is to use * solitary doublequotes or singlequotes (apostrophe) in a comment * line ... *

* @param $aMarkup String [IN] The highlight markup as returned by GeSHi; * [OUT] FALSE. * @param $aDoc String Reference to the current renderer's * doc property. * @private * @since created 04-Aug-2007 * @see render() */ function _fixGeSHi_Bash(&$aMarkup, &$aDoc) { $hits = array(); if (defined('GESHI_VERSION') && preg_match('|(\d+)\.(\d+)\.(\d+)\.(\d+)|', GESHI_VERSION, $hits) && ($hits = sprintf('%02u%02u%02u%03u', $hits[1] * 1, $hits[2] * 1, $hits[3] * 1, $hits[4] * 1)) && ('010007020' < $hits)) { // GeSHi v1.0.7.21 has the comments bug fixed $aDoc .= $aMarkup; $aMarkup = FALSE; // release memory return; } // if $lines = explode("\n", $aMarkup); $aMarkup = FALSE; // release memory while (list($i, $l) = each($lines)) { $hits = array(); // GeSHi "bash" module marks up comments with CSS class "re3": if (preg_match('|^((.*))(.*)$|i', $l, $hits)) { if ('#!/bin/' == substr($hits[3], 0, 7)) { $lines[$i] = $hits[2] . strip_tags($hits[3]); } else { $lines[$i] = $hits[1] . strip_tags($hits[3]) . ''; } // if } else if (! preg_match('|^\s*_JSmarkup) { // Markup already added (or not needed) return; } // if $localdir = realpath(dirname(__FILE__)) . '/'; $webdir = DOKU_BASE . 'lib/plugins/code/'; $css = ''; if (file_exists($localdir . 'style.css')) { ob_start(); @include($localdir . 'style.css'); // Remove whitespace from CSS and expand IMG paths: if ($css = preg_replace( array('|\s*/\x2A.*?\x2A/\s*|s', '|\s*([:;\{\},+!])\s*|', '|(?:url\x28\s*)([^/])|', '|^\s*|', '|\s*$|'), array(' ', '\1', 'url(' . $webdir . '\1'), ob_get_contents())) { $css = ''; } // if ob_end_clean(); } // if $js = (file_exists($localdir . 'script.js')) ? '' : ''; if ($this->_JSmarkup = $css . $js) { $aRenderer->doc = $this->_JSmarkup . preg_replace('|\s*

\s*

\s*|', '', $aRenderer->doc); //ELSE: Neither CSS nor JS files found. } // if // Set member field to skip tests with next call: $this->_JSmarkup = TRUE; } // _fixJS() /** * RegEx callback to markup spaces in ODT mode. * * @param $aList Array A list of RegEx matches. * @private * @static * @since created 07-Jun-2008 * @see render() */ function _preserveSpaces($aList) { return ($len = strlen($aList[1])) ? '' : ' '; } // _preserveSpaces() /** * Add the lines of the given $aText to the specified * $aDoc beginning with the given $aStart linenumber. * * @param $aText String [IN] the text lines as prepared by * handle(), [OUT] FALSE. * @param $aStart Integer The first linenumber to use; * if 0 (zero) no linenumbers are used. * @param $aDoc String Reference to the current renderer's * doc property. * @param $aClass String The CSS class name for the PRE tag. * @param $addTags Boolean Used in "ODT" mode to suppress tagging * the line numbers. * @private * @since created 03-Feb-2007 * @see render() */ function _rawMarkup(&$aText, $aStart, &$aDoc, $aClass, $addTags = TRUE) { if ($addTags) { $aDoc .= '
' . "\n";
    } // if
    if ($aStart) {
      // Split the prepared data into a list of lines:
      $aText = explode("\n", $aText);
      // Add the numbered lines to the document:
      $this->_addLines($aText, $aStart, $aDoc);
    } else {
      $aDoc .= $aText;
    } // if
    if ($addTags) {
      $aDoc .= '
'; } // if $aText = FALSE; // release memory } // _rawMarkup() /** * RegEx callback to replace SPAN tags in ODT mode. * * @param $aList Array A list of RegEx matches. * @private * @static * @since created 07-Jun-2008 * @see render() */ function _replaceSpan($aList) { return ($aList[3]) ? '' : ''; } // _replaceSpan() //@} /** * @publicsection */ //@{ /** * Tell the parser whether the plugin accepts syntax mode * $aMode within its own markup. * * @param $aMode String The requested syntaxmode. * @return Boolean FALSE (no nested markup allowed). * @public * @see getAllowedTypes() */ function accepts($aMode) { return FALSE; } // accepts() /** * Connect lookup pattern to lexer. * * @param $aMode String The desired rendermode. * @public * @see render() */ function connectTo($aMode) { // look-ahead to minimize the chance of false matches: $this->Lexer->addEntryPattern( '\x3Ccode(?=[^>]*\x3E\r?\n.*\n\x3C\x2Fcode\x3E)', $aMode, 'plugin_code'); } // connectTo() /** * Get an array of mode types that may be nested within the * plugin's own markup. * * @return Array Allowed nested types (none). * @public * @see accepts() * @static */ function getAllowedTypes() { return array(); } // getAllowedTypes() /** * Get an associative array with plugin info. * *

* The returned array holds the following fields: *

*
author
Author of the plugin
*
email
Email address to contact the author
*
date
Last modified date of the plugin in * YYYY-MM-DD format
*
name
Name of the plugin
*
desc
Short description of the plugin (Text only)
*
url
Website with more information on the plugin * (eg. syntax description)
*
* @return Array Information about this plugin class. * @public * @static */ function getInfo() { $c = 'code'; // hack to hide "desc" field from GeShi return array( 'author' => 'Matthias Watermann', 'email' => 'support@mwat.de', 'date' => '2008-07-22', 'name' => 'Code Syntax Plugin', 'desc' => 'Syntax highlighting with line numbering <' . $c . ' lang 1 |[fh] text |[hs]> ... ', 'url' => 'http://wiki.splitbrain.org/plugin:code2'); } // getInfo() /** * Define how this plugin is handled regarding paragraphs. * *

* This method is important for correct XHTML nesting. * It returns one of the following values: *

*
normal
The plugin can be used inside paragraphs.
*
block
Open paragraphs need to be closed before * plugin output.
*
stack
Special case: Plugin wraps other paragraphs.
*
* @return String "block". * @public * @static */ function getPType() { return 'block'; } // getPType() /** * Where to sort in? * * @return Integer 194 (below "Doku_Parser_Mode_code"). * @public * @static */ function getSort() { // class "Doku_Parser_Mode_code" returns 200 return 194; } // getSort() /** * Get the type of syntax this plugin defines. * * @return String "protected". * @public * @static */ function getType() { return 'protected'; } // getType() /** * Handler to prepare matched data for the rendering process. * *

* The $aState parameter gives the type of pattern * which triggered the call to this method: *

*
DOKU_LEXER_UNMATCHED
*
ordinary text encountered within the plugin's syntax mode * which doesn't match any pattern.
*
* @param $aMatch String The text matched by the patterns. * @param $aState Integer The lexer state for the match. * @param $aPos Integer The character position of the matched text. * @param $aHandler Object Reference to the Doku_Handler object. * @return Array Index [0] holds the current $aState, * index [1] the embedded text to highlight, * index [2] the language/dialect (or FALSE), * index [3] the first line number (or 0), * index [4] the top title (or FALSE), * index [5] the bottom title (or FALSE), * index [6] hidding CSS flag (or ""). * @public * @see render() * @static */ function handle($aMatch, $aState, $aPos, &$aHandler) { if (DOKU_LEXER_UNMATCHED != $aState) { return array($aState); // nothing to do for "render()" } // if $aMatch = explode('>', $aMatch, 2); // $aMatch[0] : lang etc. // $aMatch[1] : text to highlight $n = explode('>', trim($aMatch[1])); $l = 'extern'; // external resource requested? // Check whether there's an external file to fetch: if ($l == $n[0]) { if ($n[1] = trim($n[1])) { if (is_array($n[0] = @parse_url($n[1])) && ($n[0] = $n[0]['scheme'])) { // Don't accept unsecure schemes like // "file", "javascript", "mailto" etc. switch ($n[0]) { case 'ftp': case 'http': case 'https': //XXX This might fail due to global PHP setup: if ($handle = @fopen($n[1], 'rb')) { $aMatch[1] = ''; while (! @feof($handle)) { //XXX This might fail due to // memory constraints: $aMatch[1] .= @fread($handle, 0x8000); } // while @fclose($handle); } else { $aMatch = array($l, 'Failed to retrieve: ' . $n[1]); } // if break; default: $aMatch = array($l, 'Unsupported URL scheme: ' . $n[0]); break; } // switch } else { $aMatch = array($l, 'Invalid URL: ' . $n[1]); } // if } else { $aMatch = array($l, 'Missing URL: ' . $aMatch[1]); } // if } // if // Strip leading/trailing/EoL whitespace, // replace TABs by four spaces, " " by NBSP: $aMatch[1] = preg_replace( array('#(?>\r\n)|\r#', '|^\n\n*|', '|[\t ]+\n|', '|\s*\n$|'), array("\n", '', "\n", ''), str_replace(' ', ' ', str_replace("\t", ' ', $aMatch[1]))); $css = ''; // default: no initial CSS content hidding $l = FALSE; // default: no language $n = 0; // default: no line numbers $ht = $ft = FALSE; // default: no (head/foot) title $hits = array(); // RegEx matches from the tag attributes /* The free form of the RegEx to parse the arguments here is: /^ # "eat" leading whitespace: \s* (?=\S) # Look ahead: do not match empty lines. This is # needed since all other expressions are optional. # Make sure, nothing is given away once it matched: (?> # We need a separate branch for "diff" because it may be # followed by a _letter_ (not digit) indicating the format. (?> (diff) # match 1 (?>\s+([cnrsu]?))? # match 2 ) | # Branch for standard language highlighting (?> # extract language: ([a-z][^\x7C\s]*) # match 3 (?> # extract starting line number: \s+(\d\d*) # match 4 )? ) | # Branch for line numbering only (\d\d*) # match 5 | \s* # dummy needed to match "title only" markup (below) ) # "eat" anything else up to the text delimiter: [^\x7C]* (?> \x7C # extract the position flag: ([bfht])?\s* # match 6 # extract the header,footer line: ([^\x7C]+) # match 7 (?> # see whether there is a class flag: \x7C\s* (h|s)?.* # match 8 )? )? # Anchored to make sure everything gets matched: $/xiu Since compiling and applying a free form RegEx slows down the overall matching process I've folded it all to a standard RegEx. Benchmarking during development gave me free form: 20480 loops, 552960 hits, 102400 fails, 12.994689 secs standard: 20480 loops, 552960 hits, 102400 fails, 8.357169 secs */ if (preg_match('/^\s*(?=\S)(?>(?>(diff)(?>\s+([cnrsu]?))?)|' . '(?>([a-z][^\x7C\s]*)(?>\s+(\d\d*))?)|(\d\d*)|\s*)[^\x7C]*' . '(?>\x7C([bfht])?\s*([^\x7C]+)(?>\x7C\s*(h|s)?.*)?)?$/iu', $aMatch[0], $hits)) { unset($hits[0]); // free mem // $hits[1] = "diff" // $hits[2] = type (of [1]) // $hits[3] = LANG // $hits[4] = NUM (of [3]) // $hits[5] = NUM (alone) // $hits[6] = Top/Bottom flag (of [7]) // $hits[7] = TITLE // $hits[8] = s/h CSS flag if (isset($hits[3]) && ($hits[3])) { $l = strtolower($hits[3]); if (isset($hits[4]) && ($hits[4])) { $n = (int)$hits[4]; } // if $hits[3] = $hits[4] = FALSE; } else if (isset($hits[1]) && ($hits[1])) { $l = strtolower($hits[1]); $hits[2] = (isset($hits[2])) ? strtolower($hits[2]) . '?' : '?'; $n = $hits[2]{0}; $hits[1] = $hits[2] = FALSE; } else if (isset($hits[5]) && ($hits[5])) { $n = (int)$hits[5]; } // if if (isset($hits[7]) && ($hits[7])) { $hits[6] = (isset($hits[6])) ? strtolower($hits[6]) . 'f' : 'f'; switch ($hits[6]{0}) { case 'h': case 't': $ht = trim($hits[7]); break; default: $ft = trim($hits[7]); break; } // switch if (isset($hits[8])) { $hits[8] = strtolower($hits[8]) . 's'; if ('h' == $hits[8]{0}) { // This class is handled by JavaScript (there // _must_not_ be any CSS rules for this): $css = ' HideOnInit'; } // if } // if $hits[6] = $hits[7] = $hits[8] = FALSE; } // if // ELSE: no arguments given to CODE tag } // if switch ($l) { case 'console': // nothing additional to setup here break; case 'diff': if ("\n" != $aMatch[1]{0}) { // A leading LF is needed to recognize and handle // the very first line with all the REs used. $aMatch[1] = "\n" . $aMatch[1]; } // if switch ($n) { case 'u': // DIFF cmdline switch for "unified" case 'c': // DIFF cmdline switch for "context" case 'n': // DIFF cmdline switch for "RCS" case 's': // We believe the format hint ... // (or should we be more suspicious?) break; case 'r': // Mnemonic for "RCS" $n = 'n'; break; default: // try to figure out the format actually used if (preg_match( '|\n(?:\x2A{5,}\n\x2A{3}\s[1-9]+.*?\x2A{4}\n.+?)+|s', $aMatch[1])) { $n = 'c'; } else if (preg_match( '|\n@@\s\-[0-9]+,[0-9]+[ \+,0-9]+?@@\n.+\n|s', $aMatch[1])) { $n = 'u'; } else if (preg_match( '|\n[ad][0-9]+\s+[0-9]+\r?\n|', $aMatch[1])) { // We've to check this _before_ "simple" since // the REs are quite similar (but this one is // slightly more specific). $n = 'n'; } else if (preg_match( '|\n(?:[0-9a-z]+(?:,[0-9a-z]+)*)(?:[^\n]*\n.*?)+|', $aMatch[1])) { $n = 's'; } else { $n = '?'; } // if break; } // switch break; case 'htm': // convenience shortcut case 'html': // dito $l = 'html4strict'; break; case 'js': // shortcut $l = 'javascript'; break; case 'sh': // shortcut $l = 'bash'; break; default: if (! $l) { // no language: simple PRE markup will get generated $l = FALSE; } // if break; } // switch return array(DOKU_LEXER_UNMATCHED, $aMatch[1], $l, $n, $ht, $ft, $css); } // handle() /** * Add exit pattern to lexer. * * @public */ function postConnect() { // look-before to minimize the chance of false matches: $this->Lexer->addExitPattern('(?<=\n)\x3C\x2Fcode\x3E', 'plugin_code'); } // postConnect() /** * Handle the actual output (markup) creation. * *

* The method checks the given $aFormat to decide how to * handle the specified $aData. * The standard case (i.e. "xhtml") is handled completely * by this implementation, preparing linenumbers and/or head/foot * lines are requested. * For the "odt" format all plugin features (incl. linenumbers * and header/footer lines) are supported by generating the appropriate * ODT/XML markup. * All other formats are passed back to the given $aRenderer * instance for further handling. *

* $aRenderer contains a reference to the renderer object * which is currently in charge of the rendering. * The contents of the given $aData is the return value * of the handle() method. *

* @param $aFormat String The output format to generate. * @param $aRenderer Object A reference to the renderer object. * @param $aData Array The data created/returned by the * handle() method. * @return Boolean TRUE. * @public * @see handle() */ function render($aFormat, &$aRenderer, &$aData) { if (DOKU_LEXER_UNMATCHED != $aData[0]) { return TRUE; } // if if ('xhtml' == $aFormat) { if ($tdiv = (($aData[4]) || ($aData[5]))) { $this->_fixJS($aRenderer); // check for old DokuWiki versions $aRenderer->doc .= '
'; if ($aData[4]) { //XXX Note that "_headerToLink()" is supposed to be a // _private_ method of the renderer class; so this code // will fail once DokuWiki is rewritten in PHP5 which // implements encapsulation of private methods and // properties: $aRenderer->doc .= '

' . $this->_entities($aData[4]) . '

'; $aData[4] = $aData[6] = FALSE; // free mem } // if } // if if ($aData[2]) { // lang was given if ('console' == $aData[2]) { $this->_rawMarkup($this->_entities($aData[1]), $aData[3], $aRenderer->doc, $aData[2]); } else if ('diff' == $aData[2]) { $this->_entities($aData[1]); $aRenderer->doc .= '
';
          $this->_addDiff($aData[1], $aData[3], $aRenderer->doc);
          $aRenderer->doc .= '
'; } else { $isSH = ('bash' == $aData[2]); $geshi = new GeSHi($aData[1], $aData[2], GESHI_LANG_ROOT); if ($geshi->error()) { // Language not supported by "GeSHi" $geshi = NULL; // release memory $this->_rawMarkup($this->_entities($aData[1]), $aData[3], $aRenderer->doc, 'code'); } else { $aData[1] = FALSE; // free mem $geshi->enable_classes(); $geshi->set_encoding('utf-8'); $geshi->set_header_type(GESHI_HEADER_PRE); $geshi->set_overall_class('code ' . $aData[2]); global $conf; if ($conf['target']['extern']) { $geshi->set_link_target($conf['target']['extern']); } // if if ($aData[3]) { // line numbers requested // Separate PRE tag from parsed data: $aData[1] = explode('>', $geshi->parse_code(), 2); // [1][0] = leading "doc .= $aData[1][0] . '>'; // Separate trailing PRE tag: $aData[1] = explode('', $aData[1][1], 2); // [1][0] = GeSHi markup // [1][1] = trailing "_fixGeSHi_Bash($aData[1][0], $aData[1][1]); } else { // Set reference to fixed markup to sync with // the "bash" execution path (above): $aData[1][1] =& $aData[1][0]; } // if // Split the parsed data into a list of lines: $aData[2] = explode("\n", $aData[1][1]); $aData[1] = FALSE; // free mem // Add the numbered lines to the document: $this->_addLines($aData[2], $aData[3], $aRenderer->doc); // Close the preformatted section markup: $aRenderer->doc .= ''; } else { // w/o line numbering if ($isSH) { // Separate trailing PRE tag which // sometimes is "forgotten" by GeSHi: $aData[2] = explode('', $geshi->parse_code(), 2); // [1][0] = GeSHi markup // [1][1] = trailing "_fixGeSHi_Bash($aData[2][0], $aRenderer->doc); $aRenderer->doc .= ''; } else { $aRenderer->doc .= $geshi->parse_code(); } // if $geshi = NULL; // release memory } // if } // if } // if } else { $this->_rawMarkup($this->_entities($aData[1]), $aData[3], $aRenderer->doc, 'code'); } // if if ($tdiv) { if ($aData[5]) { //XXX See "_headerToLink()" note above. $aRenderer->doc .= '

' . $this->_entities($aData[5]) . '

'; } // if $aRenderer->doc .= '
'; } // if } else if ('odt' == $aFormat) { $inLI = array(); if (preg_match('|^\s*\s*(.*)$|si', $aRenderer->doc, $inLI)) { // remove leading whitespace $aRenderer->doc = $inLI[1]; } // if // The "renderer_plugin_odt" doesn't clean (close) // its own tags before calling this plugin. // To work around that bug we have to check some // private properties of the renderer instance. $inLI = FALSE; if (is_a($aRenderer, 'renderer_plugin_odt')) { if ($inLI = ($aRenderer->in_list_item)) { // If we're in a list item, we've to close the paragraph: $aRenderer->doc .= ''; } // if if ($aRenderer->in_paragraph) { $aRenderer->doc .= ''; $aRenderer->in_paragraph = FALSE; } // if } // if // Init (open) our text section: $aRenderer->doc .= "\n" . ''; if ($tdiv = (($aData[4]) || ($aData[5]))) { // Check whether we need a top caption ("header"): if ($aData[4]) { $aRenderer->doc .= '' . "\n" . $aData[4] . "\n"; $aData[4] = $aData[6] = FALSE; // free mem } // if } // if // The following code resembles the "xhtml" processing // above except that we're not using "pre" tags here // but ODT/XML markup. $aData[0] = ''; // tmp. container of processed data if ($aData[2]) { // lang was given if ('console' == $aData[2]) { $this->_rawMarkup($this->_entities($aData[1]), $aData[3], $aData[0], $aData[2], FALSE); } else if ('diff' == $aData[2]) { $this->_addDiff($this->_entities($aData[1]), $aData[3], $aData[0]); } else { $isSH = ('bash' == $aData[2]); $geshi = new GeSHi($aData[1], $aData[2], GESHI_LANG_ROOT); if ($geshi->error()) { // Language not supported by "GeSHi" $geshi = NULL; // release memory $this->_rawMarkup($this->_entities($aData[1]), $aData[3], $aData[0], '', FALSE); } else { $aData[1] = FALSE; // free mem $geshi->enable_classes(); $geshi->set_encoding('utf-8'); $geshi->set_header_type(GESHI_HEADER_PRE); $geshi->set_overall_class('code ' . $aData[2]); global $conf; if ($conf['target']['extern']) { $geshi->set_link_target($conf['target']['extern']); } // if // Separate PRE tag from parsed data: $aData[1] = explode('>', $geshi->parse_code(), 2); // [1][0] = leading "', $aData[1][1], 2); // [1][0] = GeSHi markup // [1][1] = trailing "_fixGeSHi_Bash($aData[1], $aData[2]); } else { $aData[2] = $aData[1]; } // if $aData[1] = FALSE; // release memory if ($aData[3]) { // line numbers requested // Split the parsed data into a list of lines: $aData[1] = explode("\n", $aData[2]); $aData[2] = FALSE; // release memory // Add the numbered lines to the document: $this->_addLines($aData[1], $aData[3], $aData[0]); } else { // w/o line numbers $aData[0] = $aData[2]; $aData[2] = FALSE; // release memory } // if } // if } // if } else { $this->_rawMarkup($this->_entities($aData[1]), $aData[3], $aData[0], '', FALSE); } // if if ('console' == $aData[2]) { $aRenderer->doc .= ''; } else { $aRenderer->doc .= ''; } // if // Replace the HTML "span" tags (for highlighting) by // the appropriate ODT/XML markup. // For unknown reasons we need an additional space // in front of the very first line. $aData[0] = '' . preg_replace_callback('|(]*)?>)|', array('syntax_plugin_code', '_replaceSpan'), // OOo (v2.3) crashes on " " str_replace(' ', chr(194) . chr(160), str_replace('
', '', strip_tags($aData[0], '')))); // Now append our markup to the renderer's document; // TABs, LFs and SPACEs are replaced by their respective // ODT/XML equivalents: $aRenderer->doc .= preg_replace_callback('|( {2,})|', array('syntax_plugin_code', '_preserveSpaces'), str_replace("\n", "\n", $aData[0])); $aData[0] = FALSE; // release memory // Check whether we need a bottom caption ("footer"): if ($tdiv && ($aData[5])) { $aRenderer->doc .= '' . $aData[5]; } // if // Close all our open tags: $aRenderer->doc .= "\n"; if ($inLI) { // Workaround (see above): (re-)open a paragraph: $aRenderer->doc .= ''; } // if } else { // unsupported output format $aData[0] = $aData[4] = $aData[5] = FALSE; // avoid recursion // Pass anything else back to the renderer instance // (which will - hopefully - know how to handle it): $aRenderer->code($aData[1], $aData[2]); } // if $aData = array(FALSE); // don't process this text again return TRUE; } // render() //@} } // class syntax_plugin_code } // if //Setup VIM: ex: et ts=2 enc=utf-8 : ?>
==== Presentation ==== The accompanying CSS presentation rules (using web-safe colours only): div.dokuwiki pre.code,pre.code,div.dokuwiki pre.console,pre.console{border:thin dotted #ccc;margin:1ex 0;line-height:1.33;overflow:auto;text-indent:0;max-height:40em;max-width:99%;} div.dokuwiki pre.code,pre.code{background:#fcfdfe none;color:#000;padding:0.4ex;} .code .diff_addedline{background:#cfc none;color:#000;} .code .diff_blockheader{background:#ccf none;color:#000;} .code .diff_deletedline{background:#fcc none;color:#000;} .code .br0{background:inherit;color:#369;} .code .co1,.code .co2,.code .coMULTI,.code .kw2,.code .lno{font-style:italic;} .code .br0,.code .co2,.code .es0,.code .kw1,.code .kw2,.code .kw3,.code .lno{font-weight:600;} .code .co1,.code .co2,.code .coMULTI{background:inherit;color:#666;} .code .es0{background:inherit;color:#c09;} .code .imp{background:inherit;color:#909;} .code .kw1{background:inherit;color:#903;} .code .kw2{background:inherit;color:#036;} .code .kw3{background:inherit;color:#309;} .code .kw4{background:inherit;color:#933;} .code .kw5{background:inherit;color:#00f;} .code .lno{background:inherit;color:#999;font-size:smaller;} .code .me0{background:inherit;color:#060;} .code .nu0{background:inherit;color:#939;} .code .re0{background:inherit;color:#606;} .code .re1{background:inherit;color:#660;} .code .re2{background:inherit;color:#063;} .code .re3{background:inherit;color:#963;font-style:italic;font-weight:400;} .code .re4{background:inherit;color:#099;} .code .sc0{background:inherit;color:#069;} .code .sc1{background:inherit;color:#960;} .code .sc2{background:inherit;color:#090;} .code .st0{background:inherit;color:#900;} .code .sy0{background:inherit;color:#6c6;} pre.code a{border:none;} div.dokuwiki pre.console,pre.console{background:#333 none;color:#fff;font-weight:900;padding:0.4ex 0.3ex 0.6ex 0.6ex;} div.dokuwiki pre.console .lno,pre.console .lno{background:inherit;color:#cff;font-size:smaller;font-style:italic;} div.code{margin:0.4ex 0;padding:0.4ex 0;} div.code pre.code{margin:0;} div.code p.codehead,div.code p.codefoot{color:#030;background:inherit;line-height:1.33;text-align:left;padding:0 0 0 1ex;} div.code p.codehead{margin:0.6ex 0 0 0;text-decoration:underline;} div.code p.codefoot{margin:0 0 0.6ex 0;text-decoration:underline;} div.code p.codeHidden{background-image:url(img/plus-11x11.gif);} div.code p.codeShown{background-image:url(img/minus-11x11.gif);} div.code p.codeHidden,div.code p.codeShown{padding-left:13px;background-repeat:no-repeat;background-position:0 50%;cursor:pointer;} div.code p.codeHidden:hover,div.code p.codeShown:hover{background-color:#ddffdd;color:#030;text-decoration:none;} div.code pre.codeHidden{display:none;} div.code pre.codeShown{display:block;} Of course, you're free to modify this styles((The [[http://dev.mwat.de/dw/syntax_plugin_code.zip|source archive]] contains a commented and indented stylesheet for your in­for­ma­tion.)) to suit your personal needs or aesthe­tics((Just be careful when modifying a CSS file: both the order and the selector grou­pings are im­por­tant for CSS to work as intended/expected.)). ==== Behaviour ==== Sometimes code blocks can be quite long. Long enough, anyway, to sort of overwhelm the other text of the respective page and forcing the user to scroll up/down a lot. The JavaScript file that comes with this plugin provides some additional functionality for the reader to address this issue: If you've added a [[#usage|header/footer]] line to the code block that very line becomes a //clickable area// allowing to fold (hide/show) the whole code block. The client side JavaScript accompanying this plugin uses a totaly unobtrusive approach. That means there's no mixing of markup (HTML), presentation (CSS) and behaviour (JavaScript). And if Java­Script is not available for one [[http://www.dokuwiki.org/quantserve|reason]] or another the only consequence is that there's no fol­ding feature i.e. the very same situation as the one without this plugin installed. If, however, JavaScript //is// available (and activated) at the user's side((always assuming a browser implementing the DOM standard methods)) clicking on a code block's hea­der/foo­ter line will toggle the visibility of the respective code block. Of course -- since visi­bi­li­ty, co­lour and ali­ke do not belong to the behaviour domain of JavaScript but to presentation i.e. CSS -- the script just assigns CSS classes to the respective page elements. That allows to con­fi­gure the actual chan­ges which should follow a user's click without having to learn and modify JavaScript source code: Just adjust the CSS and you're done. If -- for example -- you do not want the code block to disappear completely "on click" you could change the two very last lines of the [[#presentation|CSS]] file to something like this: div.code pre.codeHidden { max-height: 3em; } div.code pre.codeShown { max-height: 50em; } With browsers implementing the CSS correctly((which cannot be presumed with all browsers since CSS is an open standard and only ten years old)) the styling rules above will "shrink" the code block to at most three lines (instead of hidding them altogether) on click and expand the code block on the next click to at most 50 lines. The script itself defines just one (meaningless) global variable((which would not be necessary if DokuWiki's JavaScript wouldn't be the mess it is but use a proper namespace concept instead)) while encapsulating all its functionality in private members and methods. So there's little chance of naming conflicts with other JavaScript. === Folding state === Without user intervention (i.e. clicking on header/footer lines) nothing chan­ges from de­fault. That means all code blocks are visible((unless you reverse the "meaning" of the two CSS selectors mentioned above by changing the settings therein)) as one would ex­pect. After all, it would be quite unthoughtful to hide parts of a page by de­fault thus //forcing// the reader to click some­where before he/she sees the hidden con­tents. But. But there may be situations where the code block is not that important but more sort of illustration and the surrounding text should gain the user's focus first. In other words: //You// -- and not some hardcoded browser logic -- whish some block of highlighted code to be hidden initially (i.e. when the page is pre­sen­ted to the user) and become visible only on explicit user intervention (i.e. clicking). That's where the very last optional argument of the code tag comes into the play:\\ ''%%%%'' This adds some more use cases to the examples given [[#usage|above]]: * ''%%%%\\ some text\\ %%%%''\\ marks up "''some text''" as preformatted text (w/o any special highlighting) with a footer line of "''A des­crip­tion''" and the actual code block hidden ini­tially. * ''%%%%\\ some text\\ %%%%''\\ turns on HTML highlighting for "''some text''" and a header line of "''A des­crip­tion:''" with the actual code block hidden ini­tially. * ''%%%%\\ some text\\ %%%%''\\ turns on HTML highlighting for "''some text''" with added line num­bers star­ting with number ''66'' and a footer line of "''A descrip­tion''" with the actual code block hidden ini­tially. You've noticed, probably, that I didn't use the "''s''" flag here. The simple rea­son: As mentioned above the default behaviour is to ''show'' the code block any­way. Hence the "''s''" flag doesn't really change any­thing; however, I've implemented it for sym­me­try rea­sons and to allow for a more explicit markup. When implementing this folding feature I've taken great care to not exclude users with JavaScript turned off. One consequence is that code blocks you marked up using the "''hide''" flag will be //not hidden// in browsers w/o JavaScript((otherwise those users would have to disable CSS completely in their browsers to see the hidden contents)). In case you neither like nor want this folding feature, simply remove (delete or rename) the ''script.js'' file in the ''{dokuwiki}/lib/plugins/code'' di­rec­tory after [[#installation|installing]] this plugin. The non-/existence of the JavaScript file doesn't influence the [[#Plugin Source|PHP plugin]] in any way. ==== Changes ==== __2008-07-22__:\\ * CSS: added some selectors to work around DokuWiki's faulty default CSS;\\ * JS: minor internal changes (mostly adding comments);\\ * PHP: changed some misleading texts in 'handle()'; __2008-06-09__:\\ * updated CSS class names in '_addDiff()';\\ * modified '_addLines()' to use SPAN (instead of B) tags;\\ + implemented a version test in '_fixGeSHi_Bash()';\\ + implemented private '_preserveSpaces()' and '_replaceSpan()' methods for use by ODT export;\\ * added optional 'addTags' argument in '_rawMarkup()' to suppress PRE tags in ODT exports;\\ * changed whitespace handling in 'handle()' (for better OTD support);\\ + completely rewrote ODT generation in 'render()' to fully support highlighting and header/footer lines;\\ * CSS: renamed DIFF related classes (for consistency with ODT styles);\\ + added ODT stylesheet; __2008-06-02__:\\ + implemented basic support for ODT export;\\ * modified '_addLines()' to accept new 'addTags' argument;\\ # removed a superflous end tag in '_fixJS()';\\ * moved entityfication from 'handle()' to 'render()' method since the ODT plugin does this on its own;\\ * modified 'render()' method to pass unsupported data formats back to the active renderer instance; __2008-05-26__:\\ + extended 'handle()' method to retrieve external files; __2008-05-25__:\\ * CSS: added a text-indent rule (for code snippets in footnotes etc.); __2008-04-05__:\\ + implemented new ''"console"'' pseudo language keyword;\\ * replaced former private "_makeID()" method by calls of the renderer's "_headerToLink()" method; __2007-08-31__:\\ * modified "_fixGeSHi_Bash()" to omit LF if the very last line is marked up as comment; __2007-08-28__:\\ * corrected some doc typos; __2007-08-25__:\\ - removed TAB reduction in "handle()"; __2007-08-16__:\\ * minor change in "_fixGeSHi_Bash()" to omit trailing LF; __2007-08-15__:\\ * added GPL link and fixed some doc problems; __2007-08-05__:\\ + implemented another workaround in "render()" for GeSHi forgetting the trailing/closing "pre" tag in "bash" mode; __2007-08-04__:\\ + implemented private "_fixGeSHi_Bash()" method to try to fix some GeSHi errors and modified "render()" accordingly;\\ * decreased init timeout in JavaScript class;\\ + added '.re3' selector in CSS file; __2007-02-23__:\\ * several internal changes (mostly for better support of older browsers and DokuWiki releases); __2007-02-19__:\\ + implemented support for DokuWiki installations older 2006-03-05; __2007-02-11__:\\ * modified overall RegEx to require LF (to minimize false matches);\\ * improved TAB handling in "handle()";\\ + implemented optional flag/option to hide code blocks initially;\\ + added JavaScript to allow for folding code blocks; __2007-02-04__:\\ * improved handling of leading/trailing/EoL whitespace to save memory & bandwidth; __2007-02-03__:\\ * recrafted RegEx used in "handle()" to become more tolerant, faster and consuming less memory;\\ * implemented handling of GeSHi "error()"; __2007-02-02__:\\ * made some REs nonpossessive in "_addDiff()"; __2007-01-31__:\\ + implemented header/footer option;\\ * minor changes in "handle()" to make "diff" REs unpossessive; __2007-01-16__:\\ * rewrote private "_addLines()" to handle line numbers up to 999,999,999; __2007-01-12__:\\ + added 'r' option for "diff" highlighting; __2007-01-10__:\\ + implemented (recognition/highlighting of) "RCS" diff format; __2007-01-05__:\\ * moved entity replacements for blocks w/o language from "render()" to "handle()" and added some more comments; __2006-12-25__:\\ + initial release; //[[support@mwat.de|Matthias Watermann]] 2008-07-22// ===== Notes ===== Please note, that this plugin shares common problems with Do­ku­Wiki's built­in "''%%%%''" tag handler as far as the underlying "GeSHi" module is concerned. ==== Markup ==== If there's "''%%%%''" mark­up //within// the text to highlight the RegEx ba­sed par­sers will stum­ble -- with un­wan­ted re­sults((That's the reason why I changed the markup in my source doc comments from ''%%%%'' to ''%%%%'' -- a practise you could follow if you experience such a problem.)). --- Now, con­si­de­ring that (a) the //strings// "''%%%%''" and "''%%%%''" occur almost exclusively in texts marked up by (X)HTML tags and that (b) the "''%%code%%''" //tag// is an //inline// tag, one might presume that in most cases((i.e. //not// always!)) those tags will be embedded within a line of text. There­for this plugin uses slightly different patterns requiring a LF((LineFeed, char #10, "''\n''")) both im­me­di­ate­ly //af­ter the ope­ning tag// __and__ //be­fo­re the clo­sing tag// -- thus mi­ni­mi­zing (but //not// re­mo­ving) the chance of false matches. So DokuWiki markup such as bla bla bla or bla bla bla or bla bla bla will //not// be matched & handled by this plugin. However, that doesn't stop Do­ku­Wi­ki's //builtin// "''code''" hand­ler from jumping in. And since those builtin DokuWiki parsers are not designed for extensibility you have to live with this problem. While this might sound annoyingly comp-li-cated(("Nac Mac Feegle! The Wee Free Men! Nae king! Nae quin! Nae laird! Nae master! //We willna be fooled again!//")), actually, the only point you should be aware of is to //just make sure the LFs mentioned above are in place//. ==== Console ==== The ''console'' mode is intended to reproduce text such as commandline commands and their respective out­put; for example to document the installation of an application or the invocation of a program etc. You'll have to capture the output of a console session by some means((like using the ''session'' program, or redirecting the I/O from/to a file, or using the ''tee'' tool, or ...)) to be able to insert the text in a wiki page. Using ''console'' does not really produce some kind of highlighting but just places the given content in a pre­for­mat­ted (X)HTML section with accompanying styling rules to sort of resemble a raw console screen's output. You may use the optional //linenumber// and //footer/header// arguments just as with all the other languages to markup/highlight. However, in ''console'' mode the tag's content (i.e. the text between the opening and closing ''code'' tags) is just printed out as-is without analyzing or tokenizing it: plain and dump. ==== Diff ==== The problems and solution regarding "''diff''" handling are already discussed in the [[#usage]] and [[#examples]] sections above. With this plugin installed everything works as expected. ==== External Files ==== Starting with the 2008-05-26 release this plugin allows for including highlighted data from external sources. The wiki markup would look like this: extern> http://www.dokuwiki.org/lib/exe/css.php So basically instead of inserting the complete text to highlight you just enter an URI with the "''extern>''" keyword prepended. You may use any highlighting type you wish in the "''code''" tag. e.g. extern> http://www.dokuwiki.org/ would produce a numbered and highlighted listing of the given page's markup and extern> http://www.dokuwiki.org/lib/exe/js.php gives you an impression of the script code delivered to DokuWiki readers ... This feature allows you to include a highlighted version of whatever a remote server hap­pens to send back when serving your specified URI((This includes error pages such as "''404 - file not found''"!)). You should note, however, that there's no relation between the "filetype" of an URI (as indicated by a socalled filename extension) and the content-type of the data returned when serving the URI re­quest. The first example above //appears// to request a PHP file, but the returned data are of type "''text/css''", actually. The second example requests //something// (by an URI w/o any indication about a possible data type) and gets a "''text/html''" data stream. The third example, finally, again seems to request a PHP file but, in fact, gets data of type "''text/javascript''". -- So please don't confuse the URI with the data it points to. And, ah, you should //know// about the content-type of a certain URI's data when deciding which highlighting language to use: Although the examples above all point (directly or indirectly) to a PHP file none of them return a PHP source code((unless, of course, the remote server is broken)). As noted above, when using this feature to include external resources you have to live with what­ever the external server sends. Especially the formatting of the data may not suit your needs. For example, quite a few server send CSS, HTML, JavaScript etc. with­out any un­neces­sary white­space((thus saving lots af bandwidth and transfer time)) i.e. there may be no linefeeds or indentions in the data stream you receive. While that is perfectly okay for browsers it doesn't //look// too well in a wiki page, even with syntax highlighting. So you should check the resource you'd like to include with a browser's //''Show Source''// view to decide whether it's suitable for inclusion in a wiki page. Please be aware that lots of people consider it abusive to include their respective contents in foreign pages. Note as well, that including((as opposed to //linking//)) external resources could raise copy­right problems. If in doubt, just ask the re­spec­tive site operator/owner for permission before using this feature. === Limitations on external files === For security reasons the supported URI-schemes are limited to "''ftp''", "''http''" and "''https''"((ignoring e.g. "''gopher''" because I think wiki operators neither know about, nor use it anyway)). Hence it's not possible to compromise your wiki by either e.g. malicious use of the "''javascript''" or "''mailto''" pseudo schemes or the exposure of local files by the "''file''" scheme. Please note as well that this feature depends on PHP's [[http://us2.php.net/manual/en/filesystem.configuration.php#ini.allow-url-fopen|allow-url-fopen]] configuration setting. So it's //not// guaranteed to work on each and every system. Consult your PHP manual for more details about this subject. In case someone sees other security problems with this feature please drop me a [[support@mwat.de|note]]. ==== Open Document Format ==== There's an experimental [[http://www.dokuwiki.org/plugin:odt|odt plugin]] aiming to support the [[http://en.wikipedia.org/wiki/OpenDocument|Open Document Format]]. Unfortunately that plugin doesn't use the well defined XHTML markup (produced by all builtin and plugin renderers) to prepare a page for export but instead requires that each and every syntax plugin explicitely supports the ODT as well. As of 2008-06-02 [[#Plugin Source|this plugin]] provides support for the ODT export. However, you should be aware that the overall result of an ODT export might not be what you expect. Not only whole parts of a wiki page may simply disappear((mostly due to other plugins not yet implementing ODT support)). But the exported ODT file can be corrupted as well since the odt plugin((at least up to its 2008-05-07 release)) doesn't support the native DokuWiki syntax completely((For example, code fragments in list items or (block)quotes sometimes just disappear although this plugin produces the appropriate ODT/XML markup which can be found in the exported ODT's ''content.xml'' file.)). So before making ODT exports publically avail­able for your wiki pa­ges you should carefully check whether it works for you or not. Please note, that this plugin handles //only// the code fragments marked up by "''''\\ ''some text to highlight''\\ ''''" but //not// the preformatted texts in your wiki page indented by spaces or TABs. The latter are handled by the [[http://www.dokuwiki.org/plugin:odt|odt]] plugin which doesn't work properly in all constellations. If you're experiencing problems in this area try to add the ''code'' tags and see whether it helps. Anyway, as far as [[#Plugin Source|this plugin]] is concerned the text to highlight results in preformatted text, optionally with line numbers prepended (see [[#Examples]] above). The header/footer lines are placed in the ODT export as well but, of course, there's no show/hide feature in the ODT file. === ODT highlighting === To make the syntax highlighting actually work the ODT reader (e.g. [[http://why.openoffice.org/|OpenOffice.org]] writer) needs a fitting stylesheet -- just as the web-browser needs one -- to render the text. Starting with the 2008-06-09 release the plugin's [[#Installation|archive]] contains a file ''"syn­tax_plug­in_co­de_sty­les.xml"'' which provides styling rules for all the classes used by this plugin. You'll have to copy it into the ''odt'' plugin's directory to let the latter use it. Because this task cannot automaticated you'll need to change to this plugin's directory and copy the stylesheet //manually//, e.g. $> cd /to/my/dokuwiki/lib/plugins/code $> cp syntax_plugin_code_styles.xml ../odt/styles.xml $> Once you've done that all your ODT exports will use a highlighting similar to the brow­ser's [[#Presentation]]. If you miss this step the resulting ODT file should still be usable but all the code frag­ments will look like standard text -- probably not what you intend ... ==== Shell ==== The //GeSHi// module handling shell scripts ("''sh''"/"''bash''") is, well, seriously flawed (at least up to version 1.0.7.20 i.e. 2007-07-01). Especially the handling of comments with embedded strings as well as key­words is plain wrong. This plugin tries to solve some minor problems by removing high­light markup em­bed­ded in com­ment markup. This is, how­ever, by no means a fi­nal so­lu­tion: //GeSHi// ob­vious­ly keeps a kind of inte­rnal state re­sul­ting in high­ligh­ting markup span­ning (i.e. repea­ted on) seve­ral lines. Which -- if that state is wrong -- cau­ses great de­ma­ge: not by cor­rup­ting the data but by con­fu­sing the rea­der with wrong markup. The easiest way to trig­ger such a line span­ning con­fu­sion is to use so­li­tary double­quo­tes or single­quo­tes (apo­strophe) in a com­ment line as de­mon­stra­ted be­low. The following fragment will show up correctly with this plugin in­stal­led but wrong with Doku­Wiki's builtin ''code'' handler (using //GeSHi// up to v1.0.7.20): #!/bin/sh # This file is for test purposes only. # There is no other reason - # hence do not use it. echo "This test is right!" exit 0 #_EoF_ Although the words "''for''", "''test''" and "''do''" are just plain text in a com­ment line, //GeSHi// (up to v1.0.7.20) treats them as key­words. This cause of irri­ta­tion gets re­mo­ved by this plugin (as of 2007-08-04). The next fragment, however, will result in confusing highlighting: #!/bin/sh # This file is for test purposes only. # There's no other reason - # hence do not use it. echo "This test's not right!" exit 0 #_EoF_ The problem here starts with the apostrophe in line 3. Be­si­des the wrong key­word hand­ling men­tio­ned above the re­cog­ni­tion of //strings// is broken as well: The text 's no other rea­son - # hence do not use it. echo "This test' is handled as one string and the text " exit 0 #_EoF_ (i.e. up to the end of the fragment) is handled as a se­cond string. Since this kind of errors may span se­ve­ral lines (and can very well mixup the whole high­ligh­ting as the fol­lo­wing frag­ment shows) this plugin can't do any­thing about it((apart from re­pla­cing the whole "''bash''" hand­ling to by­pass //GeSHi// com­ple­tely, that is)). The only 'work­around' is to ma­nual­ly re­place the apo­stro­phes (i.e. write //"''it is''"// instead of //"''it's''"//) and single double­quo­tes((which cause the same de­sa­ster but are less likely to occur)). #!/bin/sh # It's not gonna work ... echo "This test's not right as well for all I know." # What's going on? echo "I'd rather use something else ..." # It's disturbing, isn't it? #_EoF_ A general problem with the //GeSHi// "''bash''" module is that is treats a lot of words as key­words which in fact are **not** "''bash''" key­words. It seems that some­one just dum­ped his ''/bin/'' direc­to­ries saying: "All this tools and pro­grams are shell key­words"((GeSHi's 1.0.7.20 ver­sion there­for should be avoi­ded -- or at least clean the ''KEYWORDS[2]'' array com­ple­tely (lines 64 - 118 in­clu­sive of the "''bash.php''"" file) be­cause none of its en­tries holds any ''bash'' specific key­word)). Which, of course, is plain wrong. Whoever is responsible for that mo­dule should just take a look at the ''bash'' man page to see which words and sym­bols are key­words actu­ally. -- Any­way, the con­se­quence of all the bugs men­tio­ned is that the //GeSHi// "''bash''" mo­dule is not usable for se­rious work. It cau­ses more con­fu­sion than help. **Update:** The [[http://qbnz.com/highlighter/|GeSHi]] version 1.0.7.21 (2008-03-23) seems to have at least the comment bug fixed. You might want to try installing that version over the one that came with your DokuWiki if that was an older version. ==== UTF-8 ==== Another pro­blem is that the //GeSHi// engine has a bug which cau­ses raw UTF-8 cha­rac­ter se­quen­ces in the text to highlight to end up ille­gible in some cases((The obvious rea­son seems to be that //GeSHi// un­dis­cri­mi­na­ting­ly uses PHP's builtin ''html­spe­cial­chars()'' func­tion which handles UTF-8 cha­rac­ters only in PHP 4.3 and grea­ter thus ma­king it un­us­able for e.g. wi­de­ly used RH9 in­stal­la­tions and hosted sy­stems with PHP 4.2 in­stal­led.)). As a work­around you could ma­nually "entityfy" tho­se cha­rac­ters in your page's text. ===== Backwards compatibility ===== Prior to the 2007-02-19 release of this plugin the [[#behaviour]] didn't work with Do­ku­Wi­ki re­lea­ses older than 2006-03-05((The rea­son beeing that ol­der Doku­Wiki ver­sions didn't sup­port plugin re­la­ted CSS and Java­Script files.)). But ob­vious­ly there are still quite a few ol­der ver­sions in pro­duc­tion use((As far as it was men­tio­ned the rea­son to avoid up­da­ting is that newer Doku­Wiki re­lea­ses are using PHP func­tions not avail­able with the re­spec­tive OS/PHP com­bi­na­tion.)). To sup­port such sy­stems I en­han­ced the plugin to in­clu­de the CSS and Java­Script in such ca­ses. I've te­sted it suc­cess­ful­ly with a 2005-07-30 ver­sion of Doku­Wiki, but plea­se let me know if there are is­sues with other re­lea­ses. You should be aware that the resulting XHTML code with such DokuWiki re­lea­ses does not va­li­date((while wor­king, actu­ally, at least with Fire­Fox, Opera and M$I€)) be­cause the cur­rent design of Doku­Wiki doesn't pro­vide a way to add markup to a page's ''head'' section((This is not a prob­lem spe­ci­fic to this plugin but a ge­ne­ral one with Doku­Wiki. Un­for­tu­na­te­ly its soft­ware ar­chi­tec­ture is poor­ly de­signed and a ram­pant mix of glo­bal vari­ables, func­tions and ob­jects -- a cha­rac­te­ri­stic it sha­res with a lot of other CMS' out there in the wild.)). Hence the only way to trans­port the plugin's CSS to the user's brow­ser is by em­bed­ding it in the page which, alas, ren­ders the page for­mally in­valid. The only work­around is to (a) ap­pend the plugin's CSS file to Doku­Wiki's main CSS file and (b) re­move (de­lete) the plugin's CSS file e.g.: $> cat lib/plugins/code/style.css >> lib/tpl/default/design.css $> rm -f lib/plugins/code/style.css $> _ ===== See also ===== There was another code plugin with different aims. Check its [[http://www.dokuwiki.org/plugin:code|docs]] to see whether it will fit your needs. ==== Plugins by the same author ==== * [[bomfix|BOMfix Plugin]] -- ignore Byte-Order-Mark characters in your pages * [[code2|Code Syntax Plugin]] -- use syntax highlighting of code fragments in your pages * [[deflist|Definition List Syntax Plugin]] -- use the only complete definition lists in your pages * [[diff|Diff Syntax Plugin]] -- use highlighting of diff files (aka "patches") in your pages((obsoleted by incorporating its ability into the [[code2|Code]] plugin)) * [[hr|HR Syntax Plugin]] -- use horizontal rules in nested block elements of your pages * [[lang|LANGuage Syntax Plugin]] -- markup different languages in your pages * [[lists|Lists Syntax Plugin]] -- use the only complete un-/ordered lists in your pages * [[nbsp|NBSP Syntax Plugin]] -- use Non-Breakable-Spaces in your pages * [[nstoc|NsToC Syntax Plugin]] -- use automatically generated namespace indices * [[shy|Shy Syntax Plugin]] -- use soft hyphens in your pages * [[tip|Tip Syntax Plugin]] -- add hint areas to your pages ===== Discussion ===== Hints, comments, suggestions ... Thank you for the last update ;-) > You're welcome! Hope you'll like the new [[#behaviour|folding feature]] as well.\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-02-12 12:25// ---- Hello Matthias, how can I change the default behaviour of the header/footer line * a "''h''" (for //"header"//)((or "''t''" for //"top"//)) following immediately the pipe cha­rac­ter cau­ses the remaining "''text''" to get placed //above// the code, a "''f''" (for //"foot"//)((or "''b''" for //"bottom"//)) places the "''text''" below the code (note that this flag is //optional//; if omitted it de­faults to "''f''"); I want to change the default to "''h''" = //"header"//. Or better is it possible to make this configurable?\\ Thanks -- Uwe Kirbach 2007-02-17 > Well, I designed the placement based on the model of books where you'll usu­ally find some­thing like "Listing 1" or "Example 12.4" //below// a listing. That's what readers are used to and I think it reasonable to resemble it in web pages((It's a quite important point -- but, alas, obviously unknown to many socalled "web designers" -- always to //adapt// the reader's expectations and habits but not contradict them.)). I can, however, imagine use cases where the text should appear //above// a listing and so I introduced the "''h''" and "''f''" flags to allow for con­trol­ling the text's place­ment. The default position ("''f''"oot) can be chan­ged by one single key­stroke ("''h''"). So, Uwe, I've to admit that I probably don't really understand your problem. Any­way, if you want to save that single key­stroke you can patch the plugin's ''handle()'' method: --- syntax_plugin_code.php.orig 2007-02-23 11:33:35.000000000 +0100 +++ syntax_plugin_code.php 2007-02-23 11:53:17.000000000 +0100 @@ -595,14 +595,14 @@ $n = (int)$hits[5]; } // if if (isset($hits[7]) && ($hits[7])) { - $hits[6] = (isset($hits[6])) ? strtolower($hits[6]) . 'f' : 'f'; + $hits[6] = (isset($hits[6])) ? strtolower($hits[6]) . 'h' : 'h'; switch ($hits[6]{0}) { - case 'h': - case 't': - $ht = trim($hits[7]); + case 'b': + case 'f': + $ft = trim($hits[7]); break; default: - $ft = trim($hits[7]); + $ht = trim($hits[7]); break; } // switch if (isset($hits[8])) { About your suggestion to make the default placement configurable: I don't think it's worth it to maintain((by both //you// and the plugin)) ex­ter­nal configuration files, implement the re­quired program logic and sacrifice both memory and run­time just to save a single keystroke for some use cases while requiring another keystroke for the stan­dard use case. Apart from that there is a general problem with con­fi­gu­ra­tion files & options: The writer preparing a page can not rely on a well de­fi­ned result since someone else (i.e. the wiki admin) con­fi­gures some­thing this way or the other in files the page writer has no access to((turning the writing of a page into an experience of surprises)). -- So for the time being I'd suggest to think about it and in case you're sure apply the patch given above.\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-02-18 11:44// >> Thanks, you're right about performance and complexity of configurability. The patch is enough for me. -- Uwe 2007-02-18 ---- There seems to be a bug in your highlighting. When inserting code like this: #!/bin/bash # # here's the highlighting error # ---> ... exit 1; Everything from the tick will be in red but since it is a comment, highlighting should not change. -- //Dagobert 2007-06-08// > Yes, I can confirm that problem. Please contact the [[http://qbnz.com/highlighter/|GeSHi]] developers to let them fix it. Thank you.\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-06-09 18:16// >> Even worse... I think the whole commentary thing does not work. On the example above a keyword ''for'' would also be highlighted! -- //Dagobert 2007-06-11// >>> I just checked with the latest [[http://kent.dl.sourceforge.net/sourceforge/geshi/GeSHi-1.0.7.19.tar.gz|GeSHi v1.0.7.19]] but still the same. Scanning the source, however, I found that the leading Doku­Wiki develo­per is the au­thor of the ''bash'' high­ligh­ting script as well. So pro­bably con­tacting [[andi@splitbrain.org|Andreas Gohr]] directly might help.\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-06-12 10:58// >>>> FYI, I have just checked it with the latest [[http://kent.dl.sourceforge.net/sourceforge/geshi/GeSHi-1.0.7.20.tar.gz|GeSHi v1.0.7.20]] but still the same.\\ --- //[[mischa_the_evil@hotmail.com|Mischa The Evil]] 2007-07-23 01:52// >>>>> I've implemented a workaround for //some// of the problems. See the [[#shell|shell]] section above.\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-08-05 16:56// > The [[http://qbnz.com/highlighter/|GeSHi]] version 1.0.7.21 (2008-03-23) seems to have at least the ''bash'' comment bug fixed. You might want to try installing that version over the one that came with your DokuWiki.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008-04-05 19:25// ---- The plugin doesn't seem to work with the latest dokuwiki edition 2007-06-26b... Any ideas?\\ --- //[[tetsuo@go2.pl|Tetsuo]] 2008-02-20 23:12// > Well, if you could be a little more specific -- e.g. elaborate what "doesn't seem to work" means -- someone just might have an idea. For all I know, it works without problems on numerous 2007-06-26b installations.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008-03-05 21:26// >> I was having issues with this as well (2007-06-26b) but then I spotted something very subtle between my code and the examples. In my text I was using: SELECT blah FROM BLAH which wouldn't highlight. However changing it to: SELECT foo FROM bar did. HTH\\ --- //[[fred@rizsilverthorn.net|Fred]] 2008-03-19 13:31// >>> This is discussed in the [[#Markup]] section above, Fred. Thanks for emphasizing it.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/03/26 18:35// ---- Hi, I really enjoy that plugin. I saw another plugin witch feet to my need I'm talking about [[http://www.dokuwiki.org/plugin:repo|repo]]. I would like to have both in one code2 cool features and repo capabilities to include remote code. I made quite an ugly patch for code2 to do the work, you just need to do: repo>http://my_remote_url --- //[[macfly_email@yahoo.fr|Macfly]] 2008/04/16 22:09// > Hi Macfly, please see the [[#external_files|External Files]] section above. I've in­cor­po­ra­ted that func­tio­na­lity with the plugin in a hopefully secure way. However, I changed the keyword to "''extern''" which seems more intuitive to me than "repo". I hope it helps nonetheless.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/05/26 10:25// ---- I made a basic patch to make code2 work with [[http://www.dokuwiki.org/plugin:odt|odt]] plugin: //(obsolete patch removed)//\\ --- //[[macfly_email@yahoo.fr|Macfly]] 2008/04/16 23:47// > Thanks, Macfly, for your suggestion. Please see the [[#Open Document Format]] section above. I hope you're happy with the results.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/06/02 10:59// ---- :!: I just installed this plugin (and it's excellent). I seem to have two problems: - the hide functionality doesn't seem to work (which really isn't much of a problem, unless I'm using large code blocks) - oddly the extern> function seems to **run** php code (and markup the result)! This isn't intended, right?\\ Thanks for this great plugin! //Juice 2008-06-03// > Umh, Juice, could you explain what you mean by "doesn't seem to work" with your first point? The "''hide''" fea­ture relies on a combination of presentation (i.e. CSS) and be­ha­viour (i.e. JavaScript), so if one of them is dis­abled (or doesn't work as supposed) the respective code frag­ment is //shown//. And that feature only works in com­bi­na­tion with a header/footer text (without it there wouldn't be an element to use for toggling the vi­si­bi­lity). Could you show (or send by email if it's confidential) a wiki markup frag­ment that doesn't work as you ex­pec­ted?\\ About your second point: The "''extern>''" option highlights whatever the specified URI happens to re­sol­ve to (i.e. whatever the remote server sends back, see [[#External Files|above]]). That means if you want to highlight a PHP file that is stored on a remote server you'd have to use an URI that lets the remote server return the //source code// instead of executing it. This plugin -- or any browser, for that matter -- has no way to force a remote server to send source code of server-side scripts (in whatever language) if that server does not willingly so. //If// you have ac­cess to the remote server in question you should consider pre­pa­ring some URIs for inclusion with your Doku­Wiki system (by means of this plug­in), for example you could prepare a symbolic link (e.g. ''"ln -s thescript.php thescript.php.txt"'') and then use that (latter) name in the URI of the "''extern>''" option.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/06/05 11:26// >> okay, thanks. I've got it sorted. Thanks! //Juice 2008-08-15// ---- :!:Help me. I don't know how to install. I got download file "syntax_plugin_code.zip" and upload /lib/plugins/code. But Not Operation. What is my mistake? > It appears, anonymous, that you forgot to extract the archive's contents:''\\ $\\ $ cd /path/to/dokuwiki/lib/plugins\\ $ unzip syntax_plugin_code.zip\\ Archive: syntax_plugin_code.zip\\ inflating: code/style.css\\ inflating: code/syntax_plugin_code.css\\ inflating: code/script.js\\ inflating: code/syntax_plugin_code.js\\ inflating: code/syntax_plugin_code_styles.xml\\ inflating: code/syntax.php\\ creating: code/img/\\ extracting: code/img/minus-11x11.gif\\ extracting: code/img/plus-11x11.gif\\ $''\\ Those two steps should do the trick.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/07/24 09:56// >> I solved this problem. I downloaded by Internet Explore 6.0. But downloaded file is crashed. Then I downloaded by Fire Fox 3.0. Then the zip file is not crashed. 8-O M$ is bad. ---- :?:Great plugin! I was only wondering if there would be a way to set the size of the box, and to turn on line wrapping.\\ For the first, what I mean is for example, sometimes you may want to see the full code block, without needing to move the bars.\\ About line wrapping, the geshi engine supports this, so that lines that exceed the width would be wrapped. This produces nice results combined with line numbering.\\ What do you think? > Well, Anonymous, obviously you want to change the [[#Presentation|presentation]] of your code. So just adjust its rules i.e. mo­dify the CSS according to your needs. As for the code's width re­place the ''"max-width: 99%;"'' with some­thing like ''"width: 80ex;"'' in the plugin stylesheet's first selector line.\\ To let your browser wrap the code lines add the ''"white-space: normal;"'' pre­sen­ta­tion rule in the same line. You might also want to replace the ''"overflow: auto;"'' rule by ''"overflow: visi­ble;"'' to get rid of the browser-provided scroll­bars.\\ However, if you're thinking about another markup option just have a look at the [[#Usage]] section above: There's already quite a lot of possible option arguments (and their re­spec­tive com­bi­na­tions). Adding an­other one would not only make it more difficult to re­mem­ber the correct syntax but as well would in­volve (plugin) code additions which, ironi­cally, would have to boil down to using the exact CSS rules men­tioned above.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/08/17 12:40// >> Thank you Matthias for your response! Playing with the CSS I'm able to fit my needs. On the other hand, have you realized that there is a new version of geshi? I know that it is more related to the dokuwiki distribution, but as it has some interesting new features, I tried to put it into my installation.\\ It works seamlessly, but there is an interesting improvement that splits line numbers and code into two columns of a table thus allowing you to select only the code and not the line numbers. To use that, you have to change the header type: ''$geshi->set_header_type(GESHI_HEADER_PRE_TABLE)''. However this is not working, somewhere dokuwiki seems to strip out the table part of the geshi output. It would be very nice to have a syntax highlighting such as this: http://qbnz.com/highlighter/geshi-doc.html#basic-usage.\\ >>Thank you for your attention and your plugin! >> I just got that working, changing the code on syntax.php. However, I couldn't get the PRE_TABLE to display well (it shows disaligned) so I chose to use ''GESHI_HEADER_DIV'' and ''$geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS,2)'' in case of having line numbers. In this latter case, I commented out the code for line numbering, just leaving this: >> $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS,2); $geshi->set_line_style('background: #fcfcfc;', 'background: #f0f0f0;'); // For this to work, I disabled classes $aRenderer->doc .= $geshi->parse_code(); $geshi = NULL; >> I know this is not very elegant, but it works for me(tm). I should investigate further, as this breaks folding feature (no classes, no folding). ---- :!: I just realized that line numbering isn't working for me anymore..? \\ I switched to using monobook as my template a while ago (I'm not sure if this has anything to do with it). Code highlighting appears to work well, but if I add the line number option highlighting turns off... Any ideas? //Juice 2008-08-15// > Hmm, "ideas" ... I'd //guess//, Juice, it's a problem with the template's main CSS file (e.g. too spe­ci­fic se­lec­tors there). You could try to replace all ''".code .lno"'' occurances in the plugin's stylesheet by ''"pre.code .lno"'' (which makes the respec­tive selector a little more specific) and see whether that helps. In case that doesn't work out you should provide the URL of a page demonstrating the problem. You can do this by pri­vate email if it shouldn't go public.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/08/17 12:45// ---- \\