HotChili let's you click on a colorless code listing and highlight its syntax, in fact it works in FireFox with CSS, XHTML, JavaScript, MySQL, and PHP scripts, and it's easy to customize and expand supported languages. It's based on GreaseMonkey, Chili, and jQuery.

I do need syntax highlighting to understand a program listing.
So I developed Chili to make it really easy for every author to add colors to their own code snippets.

Many sites still lack any syntax highlighting, and that bothers me.
So I developed HotChili to make it really easy for me to add colors to someone else's code snippets.

Here is a little screenshot series about the typical usage.

1- Get to a page with a colorless code snippet
2- Click on it to show the Hot Chili menu, and select the syntax you want to highlight it with
3- HotChili spices it up
4- A mistake? No problem: undo it, and retry

Valid XHTML 1.0 Strict


Install HotChili and come back here to try it against the following snippets. Then enjoy it in the wild!

CSS

/*
extracted from Drupal's chameleon theme
*/

/*
** HTML elements
*/
a, a:link, a:active {
  color: #930;
}
a:visited {
  color: #630;
}
body {
  padding: 5em 0 0 3em;
  background-image: url(background.png);
  background-repeat: repeat-x;
  font-family: trebuchet ms, tahoma, verdana, arial, helvetica;
  border-top: 10px solid gray;
}
ul {
  list-style-type: disc;
}

/*
** Page layout blocks / IDs
*/
#main {
  width: 500px;
}
#sidebar-left {
  border-right: 1px solid gray;
}
#sidebar-right {
  border-left: 1px solid gray;
}

/*
** Common declarations for child classes of node, comment, block, box etc
*/
#header .title {
  font-size: 2em;
  font-weight: bold;
  padding-top: .75em;
}
#header .title a,
#header .title a:link,
#header .title a:visited,
#header .title a:active {
  text-decoration: none;
  color: #aaa;
}
#header .title a:hover {
  color: #930;
}
#header .site-slogan {
  margin-top: -0.1em;
  font-size: 0.8em;
}
.node .title {
  font-size: 1.2em;
}
.node .title a,
.node .title a:link,
.node .title a:active,
.node .title a:visited {
  text-decoration: none;
  font-weight: normal;
}
.node .title a:hover {
  text-decoration: underline;
}
.links {
  margin: 1em 0 3em 0;
  text-align: right;
 }
.comment .content, .block .content, .menu {
  font-size: 0.9em;
}
.block {
  padding-bottom: 1em;
}
.block .title {
  font-size: 1em;
}

/*
** Module specific styles
*/
.item-list ul li {
  list-style: square;
}

JavaScript

/*  
===============================================================================
Metaobjects is the metadata plugin on steroids
...............................................................................
                                               Copyright 2007 / Andrea Ercolino
-------------------------------------------------------------------------------
LICENSE: http://www.opensource.org/licenses/mit-license.php
WEBSITE: http://noteslog.com/metaobjects/
===============================================================================
*/ 
 
( function($) { 
$.metaobjects = function( options ) { 
 
    options = $.extend( { 
          context:  document 
        , clean:    true 
        , selector: 'object.metaobject' 
    }, options ); 
 
    function jsValue( value ) { 
        eval( 'value = ' + value + ";" ); 
        return value; 
    } 
 
    return $( options.selector, options.context ) 
    .each( function() { 
 
        var settings = { target: this.parentNode }; 
        $( '> param[@name=metaparam]', this ) 
        .each( function() {  
            $.extend( settings, jsValue( this.value ) ); 
        } ); 
 
        $( '> param', this ) 
        .not( '[@name=metaparam]' ) 
        .each( function() { 
            var name = this.name, value = jsValue( this.value ); 
            $( settings.target ) 
            .each( function() { 
                this[ name ] = value; 
            } ); 
        } ); 
 
        if( options.clean ) { 
            $( this ).remove(); 
        } 
    } ); 
}; 
} ) ( jQuery );

MySQL

/* 
extracted from "Advanced MySQL user variable techniques" 
(http://www.xaprb.com/blog/2006/12/15/advanced-mysql-user-variable-techniques/)
*/

CREATE TABLE fruits (
  `type` varchar(10) NOT NULL,
  variety varchar(20) NOT NULL,
  price decimal(5,2) NOT NULL default 0,
  PRIMARY KEY  (`type`,variety)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

insert into fruits(`type`, variety, price) values
('apple',  'gala',       2.79),
('apple',  'fuji',       0.24),
('apple',  'limbertwig', 2.87),
('orange', 'valencia',   3.59),
('orange', 'navel',      9.36),
('pear',   'bradford',   6.05),
('pear',   'bartlett',   2.14),
('cherry', 'bing',       2.55),
('cherry', 'chelan',     6.33);


set @num := 0, @type := '';

select `type`, variety, price, @num
from fruits
where 2 >= greatest(
   @num := if(@type = `type`, @num + 1, 1),
   least(0, length(@type := `type`)));

PHP

/*
Plugin Name: Enzymes
Plugin URI: http://mondotondo.com/aercolino/noteslog/?cat=9
Description: The Enzymes WordPress plugin let's you EFFORTLESSLY metabolize (transclude / execute)
custom fields inside a post, a page, and everywhere in a theme. You need Enzymes.
Author: Andrea Ercolino
Version: 1.2
Author URI: http://mondotondo.com/aercolino/noteslog
*/

class Enzymes {
	var $content   = '';  // the content of the post, modified by Enzymes
	var $post      = '';  // the post which the content belongs to
	var $product   = '';  // the output of the pathway
	var $substrate = '';  // a custom field passed as additional input to an enzyme
	var $result    = '';  // the output of the enzyme
	var $e;               // array of patterns of regular expressions
	var $quote     = '='; // the quote used for fields (texturize safe and single char)

	function Enzymes() {

		//basic expressions
		$this->e = array( 
			  'post'      => '\d*'
			, 'quoted'    => $this->quote.'[^'.$this->quote.'\\\\]*'
					.'(?:\\\\.[^'.$this->quote.'\\\\]*)*'.$this->quote
			, 'oneword'   => '[\w\-]+'
			, 'star'      => '\*'
			, 'template'  => '(?:(?P<tempType>\/|\\\\)(?P<template>(?:[^\|])+))'
			, 'comment'   => '(?P<comment>\/\*.*?\*\/)'
			, 'rest'      => '(?:\|(?P<rest>.+))'
			, 'before'    => '(?P<before>.*?)'
			, 'statement' => '\{\[(?P<statement>.*?)\]\}'
			, 'after'     => '(?P<after>.*)'
		);

		//complex expressions
		$this->e['content']   = 
				'^'.$this->e['before'].$this->e['statement'].$this->e['after'].'$';

		$this->e['field']     = // this is used twice, so cannot have names for its pieces
				$this->e['quoted'].'|'.$this->e['oneword'].'|'.$this->e['star'];

		$this->e['enzyme']    = 
				'(?P<enzymePost>'.$this->e['post'].')\.(?P<enzymeField>'.$this->e['field'].')';

		$this->e['substrate'] =
				'(?P<substratePost>'.$this->e['post'].')\.(?P<substrateField>'.$this->e['field'].')';

		$this->e['subBlock']  = 
				'(?P<subBlock>\((?:'.$this->e['substrate'].')?\))';

		$this->e['block']     = 
				$this->e['enzyme'].$this->e['subBlock'].'?'.$this->e['template'].'?';

		//  X = block|block|...|block
		//    if processing X, match /block|rest*/ against X
		$this->e['pathway']   = 
				'^'.$this->e['block'].$this->e['rest'].'?$';

		//    if admitting X, match /(|head)+/ against |X
		$this->e['pathway2']  = 
				'^(?:\|'.$this->e['block'].')+$';
	}

	function apply_template( $template ) {
		if( '' != $template ) {
			$file_path = ABSPATH . '/wp-content/' . $template;
			if( file_exists( $file_path ) ) {
				ob_start();
				include( $file_path ); // include the requested template in the local scope
				$this->result = ob_get_contents();
				ob_end_clean();
			}
		}
	}

	function apply_enzyme( $enzyme ) {
		if( $this->post ) 
			$post = $this->post;
		else
			global $post;
		if( '' != $enzyme ) {
			ob_start();
			eval( $enzyme ); // evaluate the requested enzyme in the local scope
			$this->result = ob_get_contents();
			ob_end_clean();
		}
	}

	function item( $id, $key ) {
		if( $this->post ) 
			$post = $this->post;
		else
			global $post;
		if( '' == $key ) return '';
		if( '*' == $key ) { 
			if( '' == $id ) return $post->post_content;
			$a_post = get_post( $id ); 
			return $a_post->post_content; 
		}
		if( '' == $id ) $id = $post->ID;
		if( preg_match( '/'.$this->e['quoted'].'/', $key ) ) {
			// unwrap from quotes
			$key = substr( $key, 1, -1 );
			// unescape escaped quotes
			$key = preg_replace( '/\\\\'.$this->quote.'/', $this->quote, $key );
		}
		return get_post_meta( $id, $key, true );
	}

	function catalyze( $matches ) {
		$enzyme = $this->item( $matches['enzymePost'], $matches['enzymeField'] );
		if( '' == $matches['subBlock'] ) { 
			// transclusion
			$this->substrate = '';
			$this->result = $enzyme;
			if( '' != $matches['template'] ) {
				if( '/' == $matches['tempType'] ) {
					// slash template
					$this->result = $this->product . $this->result;
					$this->apply_template( $matches['template'] );
				}
				else {
					// backslash template
					$this->apply_template( $matches['template'] );
					$this->result = $this->product . $this->result;
				}
			}
			else {
				$this->result = $this->product . $this->result;
			}
		}
		else { 
			// execution
			$this->substrate = $this->item( $matches['substratePost'], $matches['substrateField'] );
			if( $enzyme ) $this->apply_enzyme( $enzyme );
			else $this->result = '';
			$this->apply_template( $matches['template'] );
			if( '' != $matches['template'] ) {
				if( '/' == $matches['tempType'] ) {
					// slash template
				}
				else {
					// backslash template
					$this->result = $this->product . $this->result;
				}
			}
		}
		$this->product = $this->result;
	}

	function cb_strip_blanks( $matches ) {
		// I suspect the $matches array is a copy without names
		$before = $matches[1];
		$quoted = $matches[2];
		$after  = $matches[3];
		$blanks = '/(?:\s|\n)+/';
		if( '' != $quoted ) {
			return preg_replace( $blanks, '', $before ) . $quoted;
		}
		else {
			return preg_replace( $blanks, '', $after );
		}
	}

	function metabolism( $content, $post = '' ) {
		if( ! preg_match( '/'.$this->e['content'].'/s', $content, $matchesOut ) ) return $content;
		else {
			$this->content = '';
			$this->post = $post;
			do {
				if( '{' == substr( $matchesOut['before'], -1 ) ) { //not to be processed
					$result = '['.$matchesOut['statement'].']}';
				}
				else {
					// erase tags
					$sttmnt = strip_tags( $matchesOut['statement'] );
					// erase blanks (except inside quoted strings)
					$sttmnt = preg_replace_callback( 
						'/(.*?)('.$this->e['quoted'].')|(.+)/s', array( $this, 'cb_strip_blanks' ), $sttmnt 
					);
					// erase comments
					$sttmnt = preg_replace( '/'.$this->e['comment'].'/', '', $sttmnt );

					if( ! preg_match( '/'.$this->e['pathway2'].'/', '|'.$sttmnt ) ) { //not a pathway
						$result = '{['.$matchesOut['statement'].']}';
					}
					else { // process statement
						$this->product = '';
						$matchesIn['rest'] = $sttmnt;
						while( preg_match( '/'.$this->e['pathway'].'/', $matchesIn['rest'], $matchesIn ) ) {
							$this->catalyze( $matchesIn );
						}
						$result = $this->product;
					}
				}
				$this->content .= $matchesOut['before'].$result;
				$after = $matchesOut['after']; // save tail, if next match fails
			} 
			while( preg_match( '/'.$this->e['content'].'/s', $matchesOut['after'], $matchesOut ) );

			return $this->content.$after;
		}
	}

	// these functions only send a simple log to my server on plugin activation / deactivation
	function makeURL( $mode ) {
		return 'http://mondotondo.com/aercolino/count/enzymes/1.2/'.$mode.'/empty.txt';
	}
	function activate() {
		$fh = fopen( $this->makeURL( 'activate' ), 'r' );
		if( false !== $fh ) fclose( $fh );
	}
	function deactivate() {
		$fh = fopen( $this->makeURL( 'deactivate' ), 'r' );
		if( false !== $fh ) fclose( $fh );
	}
}

$enzymes = new Enzymes();
add_filter( 'wp_title',        array( &$enzymes, 'metabolism' ), 10, 2 );
add_filter( 'the_title',       array( &$enzymes, 'metabolism' ), 10, 2 );
add_filter( 'the_title_rss',   array( &$enzymes, 'metabolism' ), 10, 2 );
add_filter( 'the_excerpt',     array( &$enzymes, 'metabolism' ), 10, 2 );
add_filter( 'the_excerpt_rss', array( &$enzymes, 'metabolism' ), 10, 2 );
add_filter( 'the_content',     array( &$enzymes, 'metabolism' ), 10, 2 );

function metabolize( $content, $post = '' ) {
	global $enzymes;
	echo $enzymes->metabolism( $content, $post );
}

add_action( 'activate_enzymes/enzymes-1.2.php',   array( &$enzymes, 'activate' ) );
add_action( 'deactivate_enzymes/enzymes-1.2.php', array( &$enzymes, 'deactivate' ) );

XHTML

<!-- 
extracted from "HTML 4.01 Entities Reference" 
(http://www.w3schools.com/tags/ref_entities.asp) 
-->

<hr />

<h2>ASCII Entities with new Entity Names</h2>

<table class="ex" cellspacing="0" border="1" width="100%">
    <tr>
      <th align="left">Result</th>
      <th align="left">Description</th>
      <th align="left">Entity Name</th>
      <th align="left">Entity Number</th>
    </tr>
    <tr>
      <td>&quot;</td>
      <td>quotation mark</td>
      <td>&amp;quot;</td>
      <td>&amp;#34;</td>
    </tr>
    <tr>
      <td>'</td>
      <td>apostrophe&nbsp;</td>
      <td>&amp;apos; (does not work in IE)</td>
      <td>&amp;#39;</td>
    </tr>
    <tr>
      <td>&amp;</td>
      <td>ampersand</td>
      <td>&amp;amp;</td>
      <td>&amp;#38;</td>
    </tr>
    <tr>
      <td>&lt;</td>
      <td>less-than</td>
      <td>&amp;lt;</td>
      <td>&amp;#60;</td>
    </tr>
    <tr>
      <td>&#62;</td>
      <td>greater-than</td>
      <td>&amp;gt;</td>
      <td>&amp;#62;</td>
    </tr>
</table>