When highlighting source for your website you often want to make it use a common style accross languages or want to provide multiple themes for one language. In this short howto I want to give some details on how you can actually do this.
To change the look of GeSHi provides quite a few different approaches that, depending on what you want to achieve are more or less suited for a particular usecase. But let’s start with naming the different approaches:
- The GeSHi API to set styles
- The use of language.style.php files to override styles on-load
- Using external stylesheets
- (For 1.1.X): Using native Theming Support
Let’s start analyzing all those variants one after another, providing a small example vor every one of them. The easiest way to use the GeSHi API with its various functions like set_keyword_group_style, set_comment_style and set_symbol_style. So if you want to change the style for your keywords in group 1 you probably want to use something like
$geshi->set_keyword_group_style(1, 'color: red;');
You need to repeat this for every keyword group in the language file or at least for all that you want to change. This way is especially handy if you are not only changing styles of existing keyword groups, but added additional keyword groups that need to be handled. Though you can create theming with this there’s probably a better way using one of the other ways detailled below.
Another solution offered by GeSHi to override styles is the use of a quite new feature introduced in 1.0.8 that allows you to override the whole language file styles at once. To do so you place a file called $languagename.style.php into your language file directory where $languagename is the name of the language you want to override styles for. A name for a file overriding the styles for PHP thus is named php.styles.php and might look as follows:
<?
$style_data = array(
'KEYWORDS' => array(
1 => 'color: #b1b100;',
2 => 'color: #000000; font-weight: bold;',
3 => 'color: #000066;'
),
'COMMENTS' => array(
1 => 'color: #808080; font-style: italic;',
2 => 'color: #808080; font-style: italic;',
'MULTI' => 'color: #808080; font-style: italic;' ),
'ESCAPE_CHAR' => array(
0 => 'color: #000099; font-weight: bold;'
),
'BRACKETS' => array(
0 => 'color: #66cc66;'
),
'STRINGS' => array(
0 => 'color: #ff0000;'
),
'NUMBERS' => array(
0 => 'color: #cc66cc;'
),
'METHODS' => array(
0 => 'color: #006600;'
),
'SYMBOLS' => array(
0 => 'color: #66cc66;'
),
'REGEXPS' => array(
0 => 'color: #0000ff;'
),
'SCRIPT' => array(
0 => '',
1 => '',
2 => '',
3 => ''
)
);
?>
Every time GeSHi now is asked to load the PHP language file it also loads these additional style definitions which are set incrementally, i.e. in addition to those set in the language file. Working this way you keep your application unmodified and thus without hassle when updating your installation.
Also this approach allows you to dynamically generate the styles set for GeSHi as GeSHi only reads back the $style_data array without careing how that was initialized. Thus this way is quite suited if you want a limited number of your language files to be read from a database or other store.
In case you need site-global theming you might use this too, but in general a third solution is more suiteable then: Using an external stylesheet. To do so you just have to ask GeSHi to enable use of CSS classes instead of inline styles. Every item GeSHi highlights now gets several CSS information you might use to filter it with proper CSS rules. To get a starting point for this have a look at the function get_stylesheet() that generates a stylesheet ready to be used with the current GeSHi object settings. In general such a CSS file will look something like this:
/**
* GeSHi Dynamically Generated Stylesheet
* --------------------------------------
* Dynamically generated stylesheet for php
* CSS class: , CSS id:
* GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2009 Benny Baumann
* (http://qbnz.com/highlighter/ and http://geshi.org/)
* --------------------------------------
*/
.php .de1, .php .de2 {font: normal normal 1em/1.2em monospace; margin:0; padding:0; background:none; vertical-align:top;}
.php {font-family:monospace;}
.php .imp {font-weight: bold; color: red;}
.php li, .php .li1 {font-weight: normal; vertical-align:top;}
.php .ln {width:1px;text-align:right;margin:0;padding:0 2px;vertical-align:top;}
.php .li2 {font-weight: bold; vertical-align:top;}
.php .kw1 {color: #b1b100;}
.php .kw2 {color: #000000; font-weight: bold;}
.php .kw3 {color: #990000;}
.php .kw4 {color: #009900; font-weight: bold;}
.php .co1 {color: #666666; font-style: italic;}
.php .co2 {color: #666666; font-style: italic;}
.php .co3 {color: #0000cc; font-style: italic;}
.php .co4 {color: #009933; font-style: italic;}
.php .coMULTI {color: #666666; font-style: italic;}
.php .es0 {color: #000099; font-weight: bold;}
.php .es1 {color: #000099; font-weight: bold;}
.php .es2 {color: #660099; font-weight: bold;}
.php .es3 {color: #660099; font-weight: bold;}
.php .es4 {color: #006699; font-weight: bold;}
.php .es5 {color: #006699; font-weight: bold; font-style: italic;}
.php .es6 {color: #009933; font-weight: bold;}
.php .es_h {color: #000099; font-weight: bold;}
.php .br0 {color: #009900;}
.php .sy0 {color: #339933;}
.php .sy1 {color: #000000; font-weight: bold;}
.php .st0 {color: #0000ff;}
.php .st_h {color: #0000ff;}
.php .nu0 {color: #cc66cc;}
.php .nu8 {color: #208080;}
.php .nu12 {color: #208080;}
.php .nu19 {color:#800080;}
.php .me1 {color: #004000;}
.php .me2 {color: #004000;}
.php .re0 {color: #000088;}
.php .ln-xtra, .php li.ln-xtra, .php div.ln-xtra {background-color: #ffc;}
.php span.xtra { display:block; }
As you see there is a prefix .php for each rule thus this stylesheet is limited for PHP (in this case), but can be easily reused for other languages by simply removing the .php in each rule. Note though that you need to define rules covering all language files then. Especially this means you need styles for languages like java5 that have lots of keyword styles. If you now switch your external stylesheet, defining the styles for GeSHi, to another you automatically get another theme. Easy, isn’t it?
The last way to do themeing with GeSHi is using the built-in theming support of current developement releases. Those ship with pre-build themes for some common IDEs. To use those styles you simple ask GeSHi to change to another theme and you are done. This works even to an extend that you can define subthemes like boride/d4 vs. boride/d9 (Borland IDE style for Delphi 4 which is mostly black vs. the Borland Delphi 2005 IDE style that has quite some more colors). That last possibility isn’t available in 1.0.X and will also not be backported as the styling in the developement branch is handled completely different to cope with the different output formats supported through the new renderers.
„=>“
double escaping detected =)
Kommentar by Koc — 15.12.2009 @ 20:41:46
Yeah, my bad. Missed some markup when writing the post …
Kommentar by BenBE — 15.12.2009 @ 21:14:52
Great article! I understand from the documentation that for REGEXPS you can specify the name of a function to be called, that will be given the text matched by the regex each time a match is found. An example of the syntax for that and what it can be used for would be very helpful. I’m thinking of contributing a language file for Tikiwiki syntax and this sounds like something that would be helpful.
Thanks for the great program!
lindon
Kommentar by lindon — 14.03.2010 @ 16:06:17
Yes. This is possible if you set the style for a given REGEXP group to a valid callback function. The specified function is called with the first parameter being the regexp key, the second being the matched string and the return value should be the value part of the style attribute. For more details have a look at geshi.php around lines 3511 and the GeSHi::handle_regexps_callback function.
Kommentar by BenBE — 14.03.2010 @ 21:10:36