WackoWiki: Formatter: GeSHi Code Highlighting

https://wackowiki.org/doc     Version: 79 (25.11.2022 14:29)

Formatter: GeSHi Code Highlighting

Compatible with: R6.1
Current version: 0.4
Credits:

Repo: community/formatter/highlight/geshi.php[link1]

https://github.com/GeSHi/geshi-1.0
GeSHi Documentation[link2]

1. Usage

Call via (geshi [formatter])

%%(geshi php numbers=1 start=35 lines=37) source%%

2. Install

  1. place the GeSHi lib under the lib/geshi/ folder
  2. add geshi.php highlighter to the formatter/highlight/ folder
  3. generate a external stylesheet (optional)

formatter/highlight/geshi.php[link1]
<?php

// WackoWiki Wrapper for GeSHi - Generic Syntax Highlighter
// https://wackowiki.org/doc/Dev/PatchesHacks/GeSHi

// GeSHi uses constants outside its class, so autoload will default with:
// PHP Fatal error:  Uncaught Error: Undefined constant "GESHI_NO_LINE_NUMBERS"
require_once 'lib/geshi/geshi.php'; // -> autoload.conf

if ($options['_default'])
{
    $language    = $options['_default'];
    $lines        = [];
    $numbers    = GESHI_NO_LINE_NUMBERS;
    $start        = (int) ($options['start'] ?? 1);
    $header        = GESHI_HEADER_PRE_VALID;

    $geshi = new GeSHi($text, $language);

    if (!empty($options['lines']))
    {
        $lines = array_map('intval', explode(',', $options['lines']));
        $lines = array_unique($lines);
    }

    if (!empty($options['numbers']))
    {
        $numbers = $options['numbers'] ? GESHI_NORMAL_LINE_NUMBERS : GESHI_NO_LINE_NUMBERS;

        $header = match ((int) $options['numbers'])
        {
            1        => GESHI_HEADER_PRE_VALID,
            2        => GESHI_HEADER_PRE_TABLE,
            default    => false,
        };
    }

    $geshi->enable_classes();            // use classes for highlighting (must be first after creating object)
    $geshi->set_overall_class('code');    // enables using a single stylesheet for multiple code fragments
    $geshi->set_tab_width(4);            // default: 8

    $geshi->set_header_type($header);    // GESHI_HEADER_DIV, GESHI_HEADER_PRE_VALID, GESHI_HEADER_PRE_TABLE, GESHI_HEADER_NONE

    $geshi->enable_line_numbers((bool) $numbers); // GESHI_NORMAL_LINE_NUMBERS, GESHI_FANCY_LINE_NUMBERS, 2 GESHI_NO_LINE_NUMBERS
    $geshi->start_line_numbers_at((int) abs($start));
    $geshi->highlight_lines_extra($lines);

    // get the stylesheet
    if (!file_exists(Ut::join_path(THEME_DIR, '_common/geshi.css')))
    {
        $tpl->css_styles    = $geshi->get_stylesheet(false);
    }
    else
    {
        $this->geshi = true;
    }

    $tpl->text            = $geshi->parse_code();
}
else
{
    $tpl->text            = Ut::html($text);
}


formatter/highlight/template/geshi.tpl[link3]
[ === main === ]
<ignore>
<!--notypo-->
	[= css _ =
		<style>
		[ ' styles ' ]
		</style>
	=]
	[ ' text | pre ' ]
<!--/notypo-->
</ignore>	

2.1. External stylesheet

GeSHi comes with a contrib/ directory, which in it contains a “wizard” script for creating a stylesheet. The script has been ported as a action to WackoWiki, see section below.

With up to 160 languages which one hardly will ever use, it is a good idea to generate a stylesheet with the languages you use. If you select all languages, the size of the stylesheet reaches almost 300 KiB.
There is no mixed usage of inline CSS and external stylesheet, its either one or the other. So if you select a subset, then no inline CSS is available for the other languages, consider that.

geshi.css (incomplete)
/* GeSHi - syntax highlighting code */

.code .de1, .code .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align\top;}
.code  {font-family:monospace;}
.code .imp {font-weight: bold; color: red;}
.code li, .code .li1 {font-weight: normal; vertical-align\top;}
.code .ln width:1px;text-align\right;margin:0;padding:0 2px;vertical-align\top;}
.code .li2 {font-weight: bold; vertical-align\top;}
.code .kw2 {color: #000000; font-weight: bold;}
.code .kw3 {color: #000066;}
.code .es0 {color: #000099; font-weight: bold;}
.code .br0 {color: #66cc66;}
.code .sy0 {color: #66cc66;}
.code .st0 {color: #ff0000;}
.code .nu0 {color: #cc66cc;}
.code .sc-2 {color: #404040;}
.code .sc-1 {color: #808080; font-style: italic;}
.code .sc0 {color: #00bbdd;}
.code .sc1 {color: #ddbb00;}
.code .sc2 {color: #009900;}
.code .ln-xtra, .code li.ln-xtra, .code div.ln-xtra {background-color: #ffc;}
.code span.xtra { display:block; } 	


<?php

// add to theme/_common/_header.php (above $tpl->additions)

// GeSHi styles
$this->add_html('header', '<link rel="stylesheet" href="' . Ut::join_path(THEME_DIR, '_common/geshi.css') . '">');

2.1.1. Generate custom CSS files

Script to generate custom GeSHi CSS files, only available for members of the Admin group.

action/geshicss.php
<?php

if (!defined('IN_WACKO'))
{
    exit;
}

/*

generate custom CSS files for GeSHi

{{geshicss custom=0}}

*/

if ($this->is_admin())
{
    // set defaults
    $checked    ??= null;
    $custom        ??= false;
    $wiki_text    ??= true;

    $checked    = (bool) ($_GET['all'] ?? false);
    $none        = (bool) ($_GET['none'] ?? false);

    require_once 'lib/geshi/geshi.php';

    $geshi = new GeSHi();
    $languages = $geshi->get_supported_languages();
    sort($languages);

    // [a] create stylesheet
    if (isset($_POST['langs']) && is_array($_POST['langs']))
    {
        foreach ($_POST['langs'] as $lang => $dummy)
        {
            if (in_array($lang, $languages))
            {
                $_languages[] = $lang;
            }
        }

        $tpl->enter('post_');

        foreach ($_languages as $i => $language)
        {
            $geshi->set_language($language);
            $css    = $geshi->get_stylesheet(false);
            // remove comments
            $styles    .= preg_replace('/^\/\*\*.*?\*\//s', '', $css);

            if ($wiki_text)
            {
                $tpl->enter('syntax_');

                $geshi->set_language($language);
                $tpl->n_n_num  = $i +1;
                $tpl->n_n_name = $geshi->get_language_name();
                $tpl->n_n_lang = $language;

                $tpl->leave();    // syntax_
                $tpl->commit = true;
            }
        }

        $tpl->stylesheet = $styles;
        $tpl->size = $this->binary_multiples(strlen($styles), false, true, true);
        $tpl->reset = true;
        $tpl->leave();    // post_
    }
    // [b] select languages
    else
    {
        $tpl->enter('form_');
        $tpl->n_select    = $this->href('', '', ['all' => 1]);
        $tpl->n_none    = $this->href('', '', ['none' => 1]);

        // set a preselection
        $pre_selected = [
            'css',
            'diff',
            'email',
            'html5',
            'ini',
            'javascript',
            'latex',
            'php',
            'python',
            'sql',
            'xml'
        ];

        foreach ($languages as $language)
        {
            $tpl->lang_lang        = $language;

            if ($checked || (!$none && in_array($language, $pre_selected)))
            {
                $tpl->lang_checked    = ' checked';
            }
        }

        if ($custom)
        {
            $new_lang = [
                'overall'            => ['Style for the overall code block:',
                                        'border: 1px dotted #a0a0a0; font-family: "Courier New", Courier, monospace; background-color: #f0f0f0; color: #0000bb;'],
                'default-styles'    => ['Default Styles',
                                        'font-weight:normal;background:transparent;color:#000; padding-left: 5px;'],
                'keywords-1'        => ['Keywords I (if, do, while etc)',
                                        'color: #a1a100;'],
                'keywords-2'        => ['Keywords II (null, true, false etc)',
                                        'color: #000; font-weight: bold;'],
                'keywords-3'        => ['Inbuilt Functions (echo, print etc)',
                                        'color: #000066;'],
                'keywords-4'        => ['Data Types (int, boolean etc)',
                                        'color: #f63333;'],
                'comments'            => ['Comments (//, <!--  --> etc)',
                                        'color: #808080;'],
                'escaped-chars'        => ['Escaped Characters (\n, \t etc)',
                                        'color: #000033; font-weight: bold;'],
                'brackets'            => ['Brackets ( ([{}]) etc)',
                                        'color: #66cc66;'],
                'strings'            => ['Strings ("foo" etc)',
                                        'color: #ff0000;'],
                'numbers'            => ['Numbers (1, -54, 2.5 etc)',
                                        'color: #ff33ff;'],
                'methods'            => ['Methods (Foo.bar() etc)',
                                        'color: #006600;'],
            ];

            $tpl->enter('custom_');

            foreach ($new_lang as $type => $style)
            {
                $tpl->style_type    = $type;
                $tpl->style_text    = $style[0];
                $tpl->style_style    = $style[1];
            }

            $tpl->leave();    // custom_
        }

        $tpl->leave();    // form_
    }
}


action/template/geshicss.tpl
[ === main === ]
	[= post _ =
		<div class="info type-success">
			<div class="info-content">
				<p class="info-title">Here is your completed stylesheet.</p>
				Note that it may not be perfect - no regular expression styles are included for one thing,
				you'll have to add those yourself (php and xml are just two languages that use them), and line numbers are not included, however
				it includes most of the basic information.
			</div>
		</div>
		[ '' reset ResetButton '' ]<br><br>
		<strong>theme/_common/geshi.css</strong> ([ ' size ' ])
		<pre class="code">
			[ ' stylesheet | pre' ]
		</pre>

		[= syntax _ =
			<strong>syntax wiki table</strong>
			<pre class="code">
				[ '' n table '' ]
			</pre>
		=]

		[ '' reset ResetButton '' ]
	=]

	[= form _ =
		<form action="[ ' href: ' ]" method="post" name="geshi_css">
			[ ' csrf: geshi_css ' ]
			What languages are you wanting to make this stylesheet for?<br><br>
			[ '' CreateButton '' ]<br><br>
			[ '' n selection '' ]<br>
			<div class="wrapper-col5">
			[= lang _ =
				<input type="checkbox" name="langs[[ ' lang ' ]]" id="lang_[ ' lang ' ]"[ ' checked ' ]>
				<label for="lang_[ ' lang ' ]">[ ' lang ' ]</label><br>
			=]
			</div>
			<br>
			[ '' n selection '' ]
			<br>

			[= custom _ =
				If you'd like any other languages not detected here to be supported, please enter
				them here, one per line:<br>
				<textarea rows="4" cols="20" name="extra-langs"></textarea><br>
				<br>
				Styles:
				<table>
				[= style _ =
					<tr>
						<th>[ ' text ' ]</th>
						<td><input type="text" name="[ ' type ' ]" value="[ ' style ' ]"></td>
					</tr>
				=]
				</table>
			=]

			[ '' CreateButton '' ]
		</form>
	=]

[ == selection == ]
Select: <a href="[ ' select ' ]">All</a>, <a href="[ ' none ' ]">None</a>, <a href="[ ' href: ' ]">[ ' _t: ResetButton ' ]</a><br>

[ == CreateButton == ]
<button type="submit" class="btn-ok">Create CSS</button>

[ == ResetButton == ]
<a href="[ ' href: ' ]" class="btn-link"><button type="button" class="btn-cancel">[ ' _t: ResetButton ' ]</button></a>

[ == table == ]
#|
*| # | Formatter | Language |* 
[= n _ =
|| [ ' num ' ] | ##[ ' lang ' ]## | [ ' name ' ] ||
[ ' commit | void' ]
=]
|#	

3. Supported Formats

# Formatter Language
1 4cs GADV 4CS
2 6502acme MOS 6502 (6510) ACME Cross Assembler format
3 6502kickass MOS 6502 (6510) Kick Assembler format
4 6502tasm MOS 6502 (6510) TASM/64TASS 1.46 Assembler format
5 68000devpac Motorola 68000 - HiSoft Devpac ST 2 Assembler format
6 abap ABAP
7 actionscript ActionScript
8 actionscript3 ActionScript 3
9 ada Ada
10 aimms AIMMS3
11 algol68 ALGOL 68
12 apache Apache configuration
13 applescript AppleScript
14 apt_sources Apt sources
15 arm ARM ASSEMBLER
16 asm ASM
17 asp ASP
18 asymptote asymptote
19 autoconf Autoconf
20 autohotkey Autohotkey
21 autoit AutoIt
22 avisynth AviSynth
23 awk awk
24 bascomavr BASCOM AVR
25 bash Bash
26 basic4gl Basic4GL
27 batch Windows Batch file
28 bf Brainfuck
29 biblatex BibTeX
30 bibtex BibTeX
31 blitzbasic BlitzBasic
32 bnf bnf
33 boo Boo
34 c C
35 c_loadrunner C (LoadRunner)
36 c_mac C (Mac)
37 c_winapi C (WinAPI)
38 caddcl CAD DCL
39 cadlisp CAD Lisp
40 ceylon Ceylon
41 cfdg CFDG
42 cfm ColdFusion
43 chaiscript ChaiScript
44 chapel Chapel
45 cil CIL
46 clojure Clojure
47 cmake CMake
48 cobol COBOL
49 coffeescript CoffeeScript
50 cpp C++
51 cpp-qt C++ (Qt)
52 cpp-winapi C++ (WinAPI)
53 csharp C#
54 css CSS
55 cuesheet Cuesheet
56 d D
57 dart Dart
58 dcl DCL
59 dcpu16 DCPU-16 Assembly
60 dcs DCS
61 delphi Delphi
62 diff Diff
63 div DIV
64 dos DOS
65 dot dot
66 e E
67 ecmascript ECMAScript
68 eiffel Eiffel
69 email eMail (mbox)
70 epc EPC
71 erlang Erlang
72 euphoria Euphoria
73 ezt EZT
74 f1 Formula One
75 falcon Falcon
76 fo FO (abas-ERP)
77 fortran Fortran
78 freebasic FreeBasic
79 freeswitch FreeSWITCH
80 fsharp F#
81 gambas GAMBAS
82 gdb GDB
83 genero genero
84 genie Genie
85 gettext GNU Gettext
86 glsl glSlang
87 gml GML
88 gnuplot Gnuplot
89 go Go
90 groovy Groovy
91 gwbasic GwBasic
92 haskell Haskell
93 haxe Haxe
94 hicest HicEst
95 hq9plus HQ9+
96 html4strict HTML
97 html5 HTML5
98 icon Icon
99 idl Uno Idl
100 ini INI
101 inno Inno
102 intercal INTERCAL
103 io Io
104 ispfpanel ISPF Panel
105 j J
106 java Java
107 java5 Java(TM) 2 Platform Standard Edition 5.0
108 javascript Javascript
109 jcl JCL
110 jquery jQuery
111 julia Julia
112 kixtart KiXtart
113 klonec KLone C
114 klonecpp KLone C++
115 kotlin Kotlin
116 latex LaTeX
117 lb Liberty BASIC
118 ldif LDIF
119 lisp Lisp
120 llvm LLVM Intermediate Representation
121 locobasic Locomotive Basic
122 logtalk Logtalk
123 lolcode LOLcode
124 lotusformulas Lotus Notes @Formulas
125 lotusscript LotusScript
126 lscript LScript
127 lsl2 LSL2
128 lua Lua
129 m68k Motorola 68000 Assembler
130 magiksf MagikSF
131 make GNU make
132 mapbasic MapBasic
133 mathematica Mathematica
134 matlab Matlab M
135 mercury Mercury
136 metapost MetaPost
137 mirc mIRC Scripting
138 mk-61 МК-61/52
139 mmix MMIX
140 modula2 Modula-2
141 modula3 Modula-3
142 mpasm Microchip Assembler
143 mxml MXML
144 mysql MySQL
145 nagios Nagios
146 netrexx NetRexx
147 newlisp newlisp
148 nginx nginx
149 nimrod Nimrod
150 nsis NSIS
151 oberon2 Oberon-2
152 objc Objective-C
153 objeck Objeck Programming Language
154 ocaml OCaml
155 ocaml-brief OCaml (brief)
156 octave GNU/Octave
157 oobas OpenOffice.org Basic
158 oorexx ooRexx
159 oracle11 Oracle 11 SQL
160 oracle8 Oracle 8 SQL
161 oxygene Oxygene
162 oz OZ
163 parasail ParaSail
164 parigp PARI/GP
165 pascal Pascal
166 pcre PCRE
167 per per
168 perl Perl
169 perl6 Perl 6
170 pf OpenBSD Packet Filter
171 phix Phix
172 php PHP
173 php-brief PHP (brief)
174 pic16 PIC16
175 pike Pike
176 pixelbender Pixel Bender 1.0
177 pli PL/I
178 plsql PL/SQL
179 postgresql PostgreSQL
180 postscript PostScript
181 povray POVRAY
182 powerbuilder PowerBuilder
183 powershell PowerShell
184 proftpd ProFTPd configuration
185 progress Progress
186 prolog Prolog
187 properties PROPERTIES
188 providex ProvideX
189 purebasic PureBasic
190 pycon Python (console mode)
191 pys60 Python for S60
192 python Python
193 q q/kdb+
194 qbasic QBasic/QuickBASIC
195 qml QML
196 racket Racket
197 rails Rails
198 rbs RBScript
199 rebol REBOL
200 reg Microsoft Registry
201 rexx rexx
202 robots robots.txt
203 roff roff
204 rpmspec RPM Specification File
205 rsplus R / S+
206 ruby Ruby
207 rust Rust
208 sas SAS
209 sass Sass
210 scala Scala
211 scheme Scheme
212 scilab SciLab
213 scl SCL
214 sdlbasic sdlBasic
215 smalltalk Smalltalk
216 smarty Smarty
217 spark SPARK
218 sparql SPARQL
219 sql SQL
220 sshconfig sshconfig
221 standardml StandardML
222 stonescript StoneScript
223 swift Swift
224 systemverilog SystemVerilog
225 tcl TCL
226 tclegg TCLEGG
227 teraterm Tera Term Macro
228 texgraph TeXgraph
229 text Text
230 thinbasic thinBasic
231 tsql T-SQL
232 twig Twig
233 typoscript TypoScript
234 unicon Unicon (Unified Extended Dialect of Icon)
235 upc UPC
236 urbi Urbi
237 uscript Unreal Script
238 vala Vala
239 vb Visual Basic
240 vbnet vb.net
241 vbscript VBScript
242 vedit Vedit macro language
243 verilog Verilog
244 vhdl VHDL
245 vim Vim Script
246 visualfoxpro Visual Fox Pro
247 visualprolog Visual Prolog
248 whitespace Whitespace
249 whois Whois (RPSL format)
250 winbatch Winbatch
251 wolfram Wolfram
252 xbasic XBasic
253 xml XML
254 xojo Xojo
255 xorg_conf Xorg configuration
256 xpp X++
257 yaml YAML
258 z80 ZiLOG Z80 Assembler
259 zxbasic ZXBasic

4. Changelog

0.1 Initial version
0.2 Updated to work with R.6.0
0.3 Updated to work with R.6.1, PHP 8 (Match expression)
0.4 Added template and action to create custom CSS files