CKEditor and GeSHi filter

in

Update: This approach does not involve the WYSIWYG module. It relies on the installation of CKEditor (module and editor) without a middleman management module. If you desire finer control of toolbar display by roles or HTML functionality permissions, take a closer look at the Better Formats module.

It is easier to focus on content when working with a WYSIWYG editor. I can always switch to view the source code if I need to do more complex editing. As I continue to document my Drupal experiences, I wanted to use a syntax highlighter when sharing code samples.

First, I looked at the Syntax Highlighter module. I liked the javascript functionality, ability for visitors to quickly copy the code, and other features. The drawback is that once installed, the javascript code loads on every page. Considering that only a fraction of my posts contain code, I didn't feel the performance trade-off was worth it.

Another well-reviewed solution is GeSHi (Generic Syntax Highlighter). Well supported, but little documented especially when using it with CKEditor.

An immediate interaction issue is that CKEditor correctly transcribes any special characters, such as < >, into special entities - &lt; and &gt;. Once GeSHi filter highlights the syntax, the special entities are preserved. Here is how to resolve this problem. For ease of use, I have also created a CKEditor plugin that adds five of my most used code formats to the toolbar.

Installation

Download / install / enable / configure:

To add shortuct buttons to the toolbar edit ckeditor.config.js in sites/all/modules/ckeditor:
Create new toolbar - copy DrupalFull and edit accordingly
Add new GeSHi toolbar buttons

['Geshi-code','Geshi-php','Geshi-bash','Geshi-html','Geshi-css'],

On line 26, the code checks for CKEditor version and activates Drupal specific plugins. Line 3 of the code activates the new plugin

if (Drupal.ckeditorCompareVersion('3.1')) {
  config.extraPlugins += (config.extraPlugins ? ',drupalbreaks' : 'drupalbreaks' );
  config.extraPlugins += (config.extraPlugins ? ',geshi' : 'geshi' );
}

Toolbar buttons

Functionality of the toolbar shortcut buttons:

  • In sites/all/modules/ckeditor/ckeditor/plugins create new directory geshi
  • Within the geshi directory, create file plugin.js
  • Within plugin.js define the button functions by inserting this code (download)
CKEDITOR.plugins.add( 'geshi',
{
	requires : [ 'styles', 'button' ],
 
	init : function( editor )
	{
		// All buttons use the same code to register. So, to avoid
		// duplications, let's use this tool function.
		var addButtonCommand = function( buttonName, buttonLabel, commandName, styleDefiniton )
		{
			var style = new CKEDITOR.style( styleDefiniton );
 
			editor.attachStyleStateChange( style, function( state )
				{
					editor.getCommand( commandName ).setState( state );
				});
 
			editor.addCommand( commandName, new CKEDITOR.styleCommand( style ) );
 
			editor.ui.addButton( buttonName,
				{
					label : buttonLabel,
					command : commandName
				});
		};
 
		var config = editor.config;
//		var lang = editor.lang;
 
		addButtonCommand( 'Geshi-code'		, 'code'		, 'Geshi-code'	, config.coreStyles_code );
		addButtonCommand( 'Geshi-php'		, 'php'			, 'Geshi-php'		, config.coreStyles_php );
		addButtonCommand( 'Geshi-bash'		, 'bash'		, 'Geshi-bash'	, config.coreStyles_bash );
		addButtonCommand( 'Geshi-html'		, 'html'		, 'Geshi-html'		, config.coreStyles_html );
		addButtonCommand( 'Geshi-css'		, 'css'			, 'Geshi-css'	, config.coreStyles_css );
	}
});
 
// Basic Inline Styles.
CKEDITOR.config.coreStyles_code			= { element : 'pre' };
CKEDITOR.config.coreStyles_php			= { element : 'pre', attributes : { 'language' : 'php' } };
CKEDITOR.config.coreStyles_bash			= { element : 'pre', attributes : { 'language' : 'bash' } };
CKEDITOR.config.coreStyles_html			= { element : 'pre', attributes : { 'language' : 'html4strict' } };
CKEDITOR.config.coreStyles_css			= { element : 'pre', attributes : { 'language' : 'css' } };

Toolbar button theme

If desired, it is possible to use icons for the buttons. The simpler solution is to edit your theme's css file and use the button label for the text. Code below assumes you are using the Kama skin.

.cke_skin_kama .cke_button_Geshi-code span.cke_icon,
.cke_skin_kama .cke_button_Geshi-php span.cke_icon,
.cke_skin_kama .cke_button_Geshi-bash span.cke_icon,
.cke_skin_kama .cke_button_Geshi-html span.cke_icon,
.cke_skin_kama .cke_button_Geshi-css span.cke_icon
{
  	display:none !important;
}
 
.cke_skin_kama .cke_button_Geshi-code span.cke_label,
.cke_skin_kama .cke_button_Geshi-php span.cke_label,
.cke_skin_kama .cke_button_Geshi-bash span.cke_label,
.cke_skin_kama .cke_button_Geshi-html span.cke_label,
.cke_skin_kama .cke_button_Geshi-css span.cke_label
{
  	display:inline;
  	font-size: 90%;
}

GeSHi configuration

I prefer to use the <pre> tag with an attribute. If I choose a different syntax highlighter in the future, the style will be preserved as the browser will not try to interpret the code - the default behavior for <pre> tag.

To ensure that GeSHi filter interprets the syntax within the <pre> tags, navigate to admin/settings/geshifilter/general and add pre to the Generic syntax highlighting tags. While here, enable the desired languages you want to have highlighted.

For the issue of GeSHi not converting special entities such as &lt; and &gt; open geshi.php from sites/all/modules/geshifilter/geshi and add the following code on line 2046. You can also search for "// Replace all newlines to a common form." in the existing code.

// Replace all newlines to a common form.
$code = str_replace("&gt;", ">", $code);
$code = str_replace("&lt;", "<", $code);
$code = str_replace("&lsaquo;", "‹", $code);
$code = str_replace("&rsaquo;", "›", $code);
$code = str_replace("&#39;", "'", $code);
$code = str_replace("&quot;", "\"", $code);
$code = str_replace("&amp;", "&", $code);

Input formats configuration

Enable GeSHi filter in input formats. Be sure that the GeSHi filter has higher priority than URL filter.

Clear the site and browser caches and you should see 5 new buttons in your toolbar. Ready to share some code?

There are additional ideas, such as putting the different code types into a drop-down menu, or having a dialog box open up - similar to an existing solution for Pixie.

Comments

Just FYI, I am trying to implement this as a new filter at http://drupal.org/project/wysiwyg-geshi.

This was a great little tutorial, took just a few minutes to implement get everything set up and implemented. Thanks!!

Just a little variation on this-- you can easily add geshi styles using pre tags by:

  1. add 'Styles' to the toolbar you use
  2. copy ckeditor.styles.js from sites/all/modules/ckeditor to your theme's directory
  3. edit the ckeditor.styles.js file as desired. I removed most of the styles already there and added a bunch of lines like the following for each language I wanted to list:
    { name : 'Geshi: php' , element : 'pre', attributes : { 'language' : 'php' } },

Works great and you don't need all those extra buttons.

Hello,

It is a really good mini tutorial. However, I am still having problem to replace special characters ("<",">",""") for some reason the geshifilter is not working. Do you have any idea what could be happening?

Regards
JamZiur

Did you put the space after "&" in each line of the code?

I have now adjusted the code above and put the following line at the end of the code block:

$code = str_replace("&amp;", "&", $code);

This allows for entering special character markup, such as &#39; without it being interpreted by the browser or GeSHi filter and turning them back into the special character in the code block.

Peter,

I got this to work (almost) perfectly, so thanks a ton for this.

The only problem I have is that when I apply the highlighting, a blank line gets added between each line of code. It still gets treated as a code block as a whole, but the syntax highlighting doesn't take effect. If I go in and manually delete the blank lines, then the syntax highlighting takes effect. Any ideas on what would cause that or how to fix it?

Thanks.

I think you are pasting in the code, which converts the line breaks into paragraphs <p>, then applying the code highlighting. Apply the highlighting first, then paste the code. Once you past into a <pre> block, the line breaks will not convert to a paragraph.

Updating to the latest CKEditor module (6.x-1.1) will also give you the option to force "Paste as plain text" which may help to strip out the formatting.

hmm i see no Icons in the ckEditor :(

whats wrong ? i do all in the tutorial :/

Cheers

Skull

It would be helpful to know your setup. Are you running Drupal? Which version? CKEditor module? Geshifilter module? CKEditor code? GeSHi code? Which versions? All installed in correct directories? Does it all work as expected and only giving you trouble with this particular modification?

Hello!

This is a great and rare tutorial. Thank you for writing it.

I am having the same problem as the previous comment.

All of the ckeditor buttons are blank; they are not labeled with text.

I have followed the instructions here to the letter. I can see in my plugin.js file that there are buttonLabels being added, but nothing appears? It is a blank row.

(But geshi works great!)

I've tried implementing your solution a couple of times, but without success. I've now tried the new geshi bridge, again, without success. It shows up in the wysiwyg - ckeditor, but not on the actual blog pages. Also, when I use it as code, it doesn't work. I've posted a question about it on the drupal groups pages, but no help yet. http://groups.drupal.org/node/65398#comment-198023

Any chance that you have some advice?

Based on those comments it seems that you are depending on the WYSIWYG module to manage the CKEditor interface. The steps outlined above are for a straight installation of CKEditor; in the installations I manage I also use the Better Formats module for finer control of HTML and toolbar permissions.

Thanks a million for this. Have you done the combobox idea yet? With the amount of languages I want to add to my toolbar, it seems like it would look cleaner.

Hey. First of all thank you for this great tutorial. I followed all steps and also implemented the "styles hint" suggested by "worldfallz". However, like a few others I have the problem that highlighted code is surrounded by span-tags which are somehow related to bookmarks of the ckeditor (_fck_bookmark). All I've found so far is a ticket which is about changing this to _ck_... because the "_fck" prefix was related to the fckeditor .
It' possibly related to the modification which was suggested by "worldfallz", since span tags and a _fck_bookmark attributes can be found:

"sites/all/modules/ckeditor/ckeditor/ckeditor/_source/plugins/styles/plugin.js"

I'm still trying to solve this on my own and would love to share a possible answer. If anybody can tell me how to solve this though, I would also like to avoid investigating this on my own since I'm not a JavaScript expert (yet ;).

- Versions:
* ckeditor module 6.x-1.x-dev (without wysiwyg api and without the bridge)
* latest ckeditor 3.4
* drupal core 6.19
* geshi 1.0.8.8 (using 1.0.8.4 doesnt make a difference)

- Modifications made
* geshi.php modified, special chars are translated correctly (thanks Peter!)
* Styles modification (Posted by worldfallz (not verified) on Mar 17, 2010 at 11:34)

For a description also see:
- http://drupal.org/node/890080

Any ideas about this issue?

Based on the comments and the issue posted at drupal.org I assume you are using the WYSIWYG module. The solution outlined above utilizes only the CKEditor and GeSHi module. The WYSIWYG module has some advantages, but once configured the above solution works great without need to tweak it continuously.

Hi Peter,
I'm Tony, the guy who wrote the GeSHi filter for Pixie you mentioned.
Nice article; V informative.
Although I believe my implementation is _best_ (I would, haha) your implementation is safer when untrusted users are involved.
So there's a trade off involved in both ways for developers looking for syntax highlighting plugins for CKEditor.
The two questions developers need to ask themselves are :
Can you afford the extra server load of parsing all those code blocks through GeSHi every time a visitor requests it?
And :
Can you really leave that GeSHi input dialog sitting there for a potential attacker to exploit?

So my point really is that for trusted users, I use my way but for untrusted (Site facing) user input; I'd choose your way because it's safer.

Related to syntax highlighting CKEditor plugins, I just put up a syntax highlighting source mode demo here : http://heydojo.co.cc/ckeditor-codemirror/index.html
Mainly to gauge my knowledge of the CKEditor API at this point and to show others how I implement CKEditor.

Thanks,
Tony

Thanks for your comments! I agree with the assessment that the pop-up opens up potential issues with untrusted users. As mentioned elsewhere in the comments, there has been effort to streamline the installation and configuration through the WYSIWYG module, but so far the above remains the widely used solution, especially when external users are involved.